Go语法笔记

四种声明语句

Go语言主要有四种类型的声明语句:var, const, type 和 func, 分别对应变量, 常量, 类型和函数实体

对象的声明
// 当前程序的包名(一个可执行程序只有一个 main 包)
//一般建议package的名称和目录名保持一致
package main
// 导入其它包
// 缺少或未使用的包,程序都无法编译通过
import "fmt"
// 通过 const 关键字字来进行常量的定义
const number1 = 10
// 通过 var 关键字来声明变量
var number2 = 20
// 数组
var number3 = [5]int{1, 3, 5, 7, 9}
// 集合
var number4 = map[string]int{
"Age1": 18,
"Age2": 19,
"Age2": 20,
}
// 一般类型声明
type number5 int
// 结构声明
type number6 struct{}
// 接口声明
type number7 interface{}
// 通过 func 关键字来进行函数的声明
// 只有 package 名称为 main 的包才可以包含 main 函数
func main() {
fmt.Println("Hello World")
}

操作符

比较操作符
在这里插入图片描述
在这里插入图片描述

go中类型

在这里插入图片描述
在这里插入图片描述
字符串操作
在这里插入图片描述
在这里插入图片描述

变量和常量

命名规则

  • 名字必须以一个字母或下划线开头, 后面可以跟任意数量的字母, 数字或下划线
  • 不允许使用某个关键字命名
  • Go语言中有25个关键字, 关键字不能用于命名, 只能在特定语法结构中使用
  • 根据首字母的大小写来确定可以访问的权限; 首字母大写, 可以被其他的包访问; 首字母小写, 则只能在
    本包中使用
    在这里插入图片描述
    在这里插入图片描述

变量

var a int = 1
fmt.Println(a)

//var可以声明一个或多个变量
var b, c string = "a", "b"
fmt.Println(b, c)

//声明为没有相应初始化的变量是零值的(int的零值是0, string的零值是空)
var d int
fmt.Println(d)
//Go将推断初始化变量的
//(:=)简短变量声明一般用于局部变量的声明和初始化,var往往是用在需要先指定变量类型稍后再赋值的
//不过它有一个限制,那就是它只能用在函数内部;在函数外部使用则会无法编译通过,所以一般用var方式
来定义全局变量
e := true
fmt.Println(e)

//_(下划线)是个特殊的变量名,任何赋予它的值都会被丢弃
_, f := 7, 8
fmt.Println(f)

常量

//const 可以定义一个或多个常量
const b, c = 1, 3
fmt.Println(b, c)
//表达式里可以有常量, 但不能有变量
const d = 4 - b
fmt.Println(d)
const (
	a int = iota
	b
)
const (
	a int =  1 << iota
	b
)

条件判断语句

if语句
1.条件表达式没有括号
2.支持一个初始化表达式(可以是多变量初始化语句)
3.左大括号必须和条件语句同一行

if number := 7; number < 1 {
    fmt.Println(1)
} else if number >= 1 && number <= 10 {
    fmt.Println(2)
} else {
    fmt.Println(3)
}

switch语句
switch中不需要break,因为默认不会向下贯穿执行

switch number1 := 3; number1 {
case 1:
    //如希望继续执行下一个case,可以使用fallthrough语句
    fallthrough
    fmt.Println(1)
case 3:
    fmt.Println(3)
case 5:
    fmt.Println(5)
}

for循环语句
支持3种形式
传统格式:for init; condition; post {}
while循环:for condition {}
无限循环:for {}

//形式一:
for number1 := 1; number1 < 3; number1++ {
    fmt.Printf("number1:%d\n", number1)
}
//形式二:
number2 := 1
for number2 < 3 {
    fmt.Printf("number2:%d\n", number2)
    number2++ //不能写成 number2 = number2++(++ 与 -- 是作为语句而不是作为表达式)
}
//形式三: for没有条件将无限循环;用break 退出循环
for {
    fmt.Println("loop")
    break
}

range遍历

number := [5]string{"a", "b", "c", "d", "e"}
for k, v := range number {
    fmt.Println(k, v)
}

语句跳转goto,break,continue
1.支持函数内部 goto 跳转, continue 跳出当前循环进入一下次循环,break 终止循环体
2.break 和 continue 都可以配合标签,在多级嵌套循环间跳出.这和 goto 调整执行位置完全不同
3.通常建议往后 goto,避免死循环

for number := 1; number < 5; number++ {
    if number == 3 {
      break
    }
    fmt.Println("break:", number)
}
for number := 1; number < 5; number++ {
    if number == 3 {
       continue
    }
    fmt.Println("continue:", number)
}
lable1:
for {
    for {
      //配合标签跳出最外层循环
      //标签名是大小写敏感的
      break lable1
    }
}
fmt.Println("Hello World1")
goto lable2
fmt.Println("Hello World2")
lable2:
fmt.Println("Hello World3")

数组、切片、集合、通道

数组array
1.如果在数组的长度位置出现的是“…”省略号,则表示数组的长度是根据初始化值的个数来计算
2.数组的长度必须是常量表达式,因为数组的长度需要在编译阶段确定

number1 := [3]int{1, 2, 2: 3}
number2 := [3][4]int{
{1, 2, 3, 4},
{5, 6, 7, 8},
{0: 9, 1: 10, 2: 11, 3: 12},
}

number4 := [...]int{3, 1, 9, 6, 8}

由于数组长度固定,所以不可新增,删除,只能更新
切片slice
[]T,T为类型
1.make([]T, length长度, capacity容量)
2.一般使用make()创建 : 用len获取切片长度, cap获取切片容量
3.一个切片在未初始化之前默认为 nil,长度为 0
4.与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大

切片复制copy()
copy 函数copy从源slice的src中复制元素到目标dst,并且返回复制的元素的个数

number1 := []int{1, 2, 3, 4, 5}
number2 := []int{6, 7, 8}
number3 := copy(number1, number2)
fmt.Println(number1, number2, number3)
结果:
[6 7 8 4 5]  [6 7 8]  3

追加append

number1 := []int{1, 2, 3}
fmt.Println(number1, len(number1), cap(number1))
number1 = append(number1, 4, 5)
fmt.Println(number1, len(number1), cap(number1)) //按初始容量成倍扩大
number3 := append(number1, number1...) //用省略号自动展开切片,以使用每个元素
fmt.Println(number3)
结果:
[1 2 3] 3 3
[1 2 3 4 5] 5 6
[1 2 3 4 5 1 2 3 4 5]

删除

删除下标是index的元素
slice = append(slice[ : index ] , slice[ index+1 : ])
删除头部元素
slice = slice[1:]
删除尾部
slice = slice[:len(slice) -1]

遍历slice

 number := [5]string{"a", "b", "c", "d", "e"}
for k, v := range number {
        fmt.Println(k, v)
  }

集合map
map[T1]T2,T1为键的类型,T2为值的类型,键的类型必须是支持==或!=比较运算的类型
1.map的迭代顺序是随机的
2.若想按指定顺序遍历map,先将键取出放入一个slice,然后对键排序,按键序访问map

number3 := map[int]string{1: "a", 2: "b", 3: "c", 4: "d", 5: "e"}
number4 := make([]int, len(number3))
i := 0
for k, v := range number3 {
    fmt.Println(k, v)
    number4[i] = k
    i++
}

删除map元素delete()
delete(map, key)
访问map元素
value,ok = map[key],如果key存在,则返回值value和nil,如果不存在,返回零值和false
添加与更新
map[key] = value 若key不存在则添加,存在则更新

通道channel
1.go 关键字用来创建 goroutine (协程),是实现并发的关键
2.channel 用来进行多个goroutine通信的,可以设置缓存大小,在未被填满前不会发生阻塞(默认为0,
无缓冲)
3.无缓冲的信道是一批数据一进一出, 有缓冲的信道则是一个一个存储,然后一起流出去
4.select 可以处理一个或多个 channel 的发送与接收

使用 make(chan val-type) 创建一个新的通道
ch := make(chan int)
//go 关键字创建一个协程
go loop(ch)
go loop(ch)
func loop(ch chan int) {
    for i := 0; i < 8; i++ {
        fmt.Println(i)
    }
    ch <- 1 //发送值到通道
}

关闭通道close
close(ch)

函数、结构体、方法、接口

函数

func main() {
    fmt.Println(Add(8, 7))
    fmt.Println(Subtraction(8, 7))
}
func Add(number1 int, number2 int) (number3 int) {
    number3 = number1 + number2
    return
}
func Subtraction(number1, number2 int) int {
    number3 := number1 - number2
    return number3
}

匿名函数

//匿名函数1
//f1 为函数地址
f1 := func(x, y int) (z int) {
    z = x + y
    return
}
fmt.Println(f1)
fmt.Println(f1(5, 6))
 
//匿名函数2
//直接创建匿名函数并运行
f2 := func(x, y int) (z int) {
    z = x + y
    return
}(7, 8)
fmt.Println(f2)

//匿名函数3(无参数的形式)
func() {
    fmt.Println(9 + 10)
}() //不明白为什么后面要加个括号

闭包函数

func main() {
    //函数内在包含子函数,并最终return子函数
    n1 := number1(7)
    fmt.Println(n1(8))
    n2 := number2()
    n2()
}

结构体struct
把各种数据类型定义的不同变量组合起来

type Person struct {
    Name string
    Age int
}

方法

type Calculation struct {
    number1 int
    number2 int
}
func (c Calculation) Add() int {
    number3 := c.number1 + c.number2
    return number3
}

接口interface
1.go中只要某个类型拥有该接口的所有方法签名,即算实现该接口,不需要显示指定
2.任何类型都实现了空接口 interface{}
type geometry interface {
area() int64
perimeter() int64
}

指针
操作符"&“取变量地址,使用”*"通过指针间接访问目标对象

number1 := 10
var number2 *int = &number1
fmt.Println(number2)
fmt.Println(*number2)

传值与传指针

  • 当我们传一个参数值到被调用函数里面时,实际上是传了这个值的一份copy,当在被调用函数中修改参数值的时候,调用函数中相应实参不会发生任何变化,因为数值变化只作用在copy上
  • 变量在内存中是存放于一定地址上的,修改变量实际是修改变量地址处的内存
  • 传指针使得多个函数能操作同一个对象
  • 传指针比较轻量级 (8bytes),只是传内存地址,我们可以用指针传递体积大的

猜你喜欢

转载自blog.csdn.net/qq_25744595/article/details/85681557