go基础
声明变量
eg:
name := "name"
age := 1
result := false
变量声明的零值,也就是默认值,eg:
var a int
var b float64
var c bool
var d string
输出是 0 "" false 0
数组和切片
数组可以这样声明
array := [...]int{1,2,3}
切片可以这样声明
slice := []int{1,2.3}
一般遍历的时候,都用切片遍历,切片可以用append往后边追加元素,eg:
slice2 := append(slice,"f","d"),追加后的切片,指向了一个新的变量名slice2
make函数
make函数只能用在切片(slice) 映射/也就是字典(map)和chan的初始化上
字面量
常用的3中字面量
1,表示基础数据类型的值的各种字面量
2,构造各种自定义的复合函数类型的类型字面量
3,用来够着类型struct(结构体)、Array(数组)、Slice(切片)和Map(字典)的值,一般由值的字面量类型加大括号组合起来符合使用,eg:
nameAgeMap := map[string]int{"飞雪无情":20} // 这是字典,又叫映射
slice := []int{1,2.3} // 切片
array := [...]int{1,2,3} // 数组
遍历
遍历都是用for range ,eg:
数组遍历 for i,v := range array{} i是下标,也就是索引,v是具体的值
字典遍历 for k,v := range map{} k是kay,v是value
字符串遍历 for i,r := range string{} 这里需要注意,如果是汉字,会被当成unicode编码的,一盒汉字当成3个长度遍历的
字符串长度
如果直接用len(string)来算字符串的长度,一个汉字会对应三个字节,等于长度会被*3
要想用一个汉字当一个长度,用utf8.RuneCountlnString,eg:
fmt.Println(utf8.RuneCountlnString(String))
函数
比较常见的函数结构如下:
func sun(a,b,params ...int) (result,err) {}
func 是函数固定开头
sun是函数名字(小写就是私有函数)
紧挨着sun的括号里,是函数的参数,a和b 是定长参数,一个萝卜一个坑,params ...int 这种写法就是变长参数,可以传多个参数
最后一个括号里是函数的返回,在函数定义的时候就写好要返回的结果,下边函数结束时,可以只写一个return就可
函数的公有私有
函数名字大写,如Pringln就是共有函数,可以跨包调用,函数名字小写如sum,就是私有的函数
闭包
函数嵌套,在外边一个正常定义的函数里,可以再定义一个匿名函数,这个匿名函数还能用外部函数的参数,这就是闭包。eg:
func colsure() func() int {
i := 0
return func() int {
i++
return i
}
}
上边这个例子,匿名函数既可以作为外部函数colsure,在定义函数的时候填写的返回值,也可以在函数内部,用return返回,这种就是流式编程,把函数作为另外一个函数的参数。
方法
方法的声明,eg:
type Age int func (a Age) String(){ fmt.Pringln("年龄是:",a) }
String()就是类型是Age的方法,类型Age就是方法 String()的接受者,但是这接受者,都要用小括号圈起来,小括号里,第一个是变量名,第二个是具体的接受者。所以func 后边紧跟着的第一个括号里的(a Age),就是方法String()的接受者,下边说方法的接受者,指的就是(a Age)
方法的调用,下边的代码示例省略了main()函数
age := Age(25) age.String()
注意,给方法传参数,得放到类型Age里,然后,赋值给变量age,这样age直接点String(),蚕食就直接通过接受者里的变量名a,拿到了,然后就执行了方法里的代码。
值类型接受者和指针类型接受者。
type Age int func (a Age) Strings() { fmt.Println("SDSD",a) } func (a *Age) String() { *a = Age(30) }
然后在main()函数里调用方法
age := Age(25) age.Strings() age.String() age.Strings()
然后就发现输出第一行是25,第二行就变成了30
几个点
1,一个Age类型可以有多个方法,比如Strings()和String()
2,在方法String()中,接受体(a *Age),是把指针标志落到类型本体上
3,在main()函数里,调用方法的时候,除了可以使用值类型变量,还可以使用指针类型变量,eg:(&a).String()。
age := Age(25) age.Strings() (&age).String() age.Strings()
4,用点可以点出方法名
5,在调用方法的时候,指针类型的就得用&符号,eg: (&age).String()
6,声明方法的时候,接受体里的指针是落到类型本体,但是方法里边用这个指针,得落到那个变量名上,eg:
func (a *Age) String() { *a = Age(30) }
方法表达式
方法直接赋值给一个变量,就是方法表达式
声明一个结构体
type person struct {
name string
age uint
}
在结构体中,name和age被称为成员名/字段名。结构体里边可为空
实例化一个结构体
eg: p := person{age:30}
访问一个结构体的字段和调用一个类型的方法(调用一个类型的方法,意思就是方法上边得跟着一个type Age int,意思就是得提前指定这个方法的类型,所以才会说,调用一个类型的方法)一样都是点。还是用上边的例子,eg:
结构体,p.age
方法
接口
要实现一个接口,必须实现这个接口提供的所有方法,而接口是实现者必须是一个具体的类型,比如接口体。eg:
// 声明一个结构体 type age struct { name string sex int ass adress } // 声明结构体age 里边的嵌套结构体adress type adress struct { add string mobile int } // 定义一个接口Stringers,里边有个方法String() type Stringers interface { String() (string,int) } // 上边接口里,调用的那个方法String(),返回的是字符串,注意方法和函数的区别,就是方法前边有个(a,age), // 反应过来方法和函数的区别的了,在函数前边加上方法特有的(a age),就类似于css起了一个类名,然后都是div标签, // 用结构体age实现接口Stringers func (a age) String() (string,int) { return fmt.Sprintf("sex是:%d,名字是:%s",a.sex,a.name),a.sex } // 再用结构体ass实现接口Stringers func (add adress) String() (string,int){ return fmt.Sprintf("手机号是:%d,地址是:%s",add.mobile,add.add),add.mobile } // 再声明一个函数,打印上边的接口Stringers,这个函数只有参数s,没有返回值 func printStrings(s Stringers) { fmt.Println(s.String()) }
最后再在main()函数里调用函数printStriger,传参数
func main() { a := age{name: "sad",sex: 12,ass:adress{add: "ssd",mobile: 1212121212}} //这是初始化一个结构体age,用的是结构体字面量的方式初始化的,没有初始化到的值,是空,然后把初始化出的结构体,赋值给一个变量,也就是a //fmt.Println(a.ass.mobile) printStrings(a) // 函数printStrings,在这里调用,参数是定长的变量a.补充,变长的参数是这样params ...int,放到参数的最后边,注意,函数里,处理这里变长的参数params,一般是用for range 遍历出来的 printStrings(a.ass) // 因为结构体age,里边有嵌套的ass,所以可以直接这样点出来 //有个疑问,为什么这里调用函数里传的参数是变量a,这个a其实就是一个初始化的结构体,但是下边函数里接受的参数,是接口Stringers //反应过来了,调用的地方,先把变量a传进去,然后声明函数的地方,参数是Stringers,所以参数a其实被传进来到接口Stringers中了 //然后接口Stringers中,调用了方法String,并规定了返回的参数是两个,一个是字符串,一个是数字 //然后下边有两个方法,然后这俩方法的方法名一样,但是接受者不一样,因为定义了两个结构体,所以这两个机构体都作为接口的实现者去实现这个接口的方法,就都可以被实现了。一个接口,调用一个方法名,然后对应的接受者不同的方法就都被实现了 }
值接受者和指针接受者
直接写结论,还是用上边那个例子里的。(方法接受者就是方法前边第一个括号里的)eg:
1,当用值类型的方法接受者时:func (a age) String() (string,int) {},下边的实现接口的类型,有两种选择:
1)printStrings(a) // 接口体类型的实现接口的类型
2)printStrings(&a) // 指针类型的实现接口的类型
2,当用指针类型的方法接受者时:func (a *age) String() (string,int) {},下边的实现接口的类型,只有一种选择:
1)printStrings(&a) // 指针类型的实现接口的类型