[TOC] ## 整数 ## 数字类型 变量赋值时,一般都采用有符号整型 1. 无符号整型 ``` uint8 //1 个字节 0-255 uint16 //2 个字节 0-65535 uint32 //3 个字节 0-4294967295 uint64 //3 个字节 0-18446744073709551615 ``` 2. 有符号整型 ``` int8 //1 个字节 -128-127 int16 //2 个字节 -32768-32767 int32 //3 个字节 -2147483648-2147483647 int64 //3 个字节 -9223372036854775808-9223372036854775807 ``` ## 浮点型 变量赋值时,一般都采用float64,float32 在计算时候容易缺失精度 ``` float32 //32位浮点型数 float64 //64位浮点型数 complex64 //32 位实数和虚数 complex128 //64 位实数和虚数 ``` ## 其他数字类型 ``` byte //uint8 rune //int32 uint //32 或 64 位 根据系统决定 int //与 uint 一样大小 uintptr //无符号整型,用于存放一个指针 ``` ## 字符串类型 ``` hw1 := "世界" hw2 := "\xe4\xb8\x96\xe7\x95\x8c" hw3 := "\u4e16\u754c" hw4 := "\U00004e16\U0000754c" // 它们的值都是相同的 fmt.Printf("%+v\n", hw1) // 世界 fmt.Printf("%+v\n", hw2) // 世界 fmt.Printf("%+v\n", hw3) // 世界 fmt.Printf("%+v\n", hw4) // 世界 ``` - 对于小于256码点值可以写在一个十六进制转义字节中,例如\x41对应字符'A',但是对于更大的码点则必须使用\u或\U转义形式。因此,`\xe4\xb8\x96` ( 世 ) 并不是一个合法的rune字符,虽然这三个字节对应一个有效的UTF8编码的码点 ## 指针类型( Pointer) ### 指针赋值 ``` var a = 3 var p = &a //取内存值 *p = 4 fmt.Println(a) //0xc042052080 fmt.Println(p) //4 ``` ### 指针传参 ``` func swap(a *int) { *a++ } a := 3 swap(&a) fmt.Println(a) //4 ``` ## 数组类型 (在 go 语言中一般不使用数组,推荐切片) ``` //初始化赋值 var a[5] a[0]=12 var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0} //自动识别长度 var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0} //多维数组 b :=[][]int { {1,2,3}, {3,24,35}, {11,22,33}, } ``` ``` type Currency int const ( USD Currency = iota // 美元 EUR // 欧元 GBP // 英镑 RMB // 人民币 ) symbol := [...]string{USD: "$", EUR: "€", GBP: "£", RMB: "¥"} fmt.Println(RMB, symbol[RMB]) // "3 ¥" ``` ## 切片类型( slice) 1.切片的创建方式 基于底层数组创建,直接创建,或者 make() 函数创建 1. 与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。会进行分配内存和 copy 操作 1. len() 方法获取长度。 3. 添加切片 `append` 与拷贝切片 `copy` ``` //创建 a :=[]int {10,20,30,40,50,60,70} b :=a[1:3] //{20,30} c :=a[1:] //{20,30,40,50,60,70} d :=a[:3] //{10,20,30} //添加贴片 var numbers =[]int{1,2,3} /* 允许追加空切片 */ numbers = append(numbers, 3) fmt.Println(numbers) //[1 2 3 3] /* 拷贝 numbers 的内容到 numbers1 */ copy(numbers1,numbers) //len=3 cap=8 slice=[0 1 2] ``` > 区别 ``` a :=[]int{1,2,3} //切片 b :=[...]int{1,2,3} //数组 c :=b[:] //从数组中生成切片 fmt.Println(reflect.TypeOf(a))//[]int fmt.Println(reflect.TypeOf(b)) //[3]int fmt.Println(reflect.TypeOf(c)) //[]int -切片 值为[1 2 3] ``` ### make([]int) 指定的长度根据真实长度扩展 ``` a := make([]int, 2, 3) fmt.Println(len(a)) //2 fmt.Println(cap(a)) //3 a = append(a, 2, 2, 2) fmt.Println(len(a)) //5 fmt.Println(cap(a)) //6 ``` ## Channe|类型(chan) 不能超过设置的长度 ``` person := make(chan int) //默认的长度只有1,超出后报错 person <- 12 person <- 23 //fatal error: all goroutines are asleep - deadlock! ``` ### chan 返回最快结果的用法 多个goroutines并发地向同一个channel发送数据,或从同一个channel接收数据都是常见的用法 ``` func mirroredQuery() string { responses := make(chan string, 3) go func() { responses <- request("asia.gopl.io") }() go func() { responses <- request("europe.gopl.io") }() go func() { responses <- request("americas.gopl.io") }() return <-responses // return the quickest response } ``` ## 函数类型(func) ``` //int 类型也可改为 a ...interface{} 传 demo(3,4,"5") func demo(a ...int){ fmt.Print(a) //[3 4 5] } demo(3,4,5) ``` ### 复杂传值 ``` func demo(a ...interface{}){ fmt.Print(a) //[3 4 5 [3 4 5]] } a :=[]interface{}{3,4,5} demo(3,4,5,a) ``` ### 函数参数为数组时的长度需相等 ``` func demo(a [5]int){ fmt.Println(a) } //ok a :=[5]int{1,2,3,4,5} demo(a) //error a :=[3]int{1,2,3} demo(a) ``` ### 函数当作参数传值 ``` func compute(fn func(int, int) int) int { return fn(3, 4) } func main() { c := compute(add) fmt.Println(c) } func add(a, b int) int { return a + b } ``` ### 函数当参数 ``` type Callback func(x, y int) int ``` ### 闭包函数 - 实现斐波那契数组 函数返回前的变量不会改变 ``` func fibonacci1() func() int { back1, back2 := 0, 1 // 该值初始化一次,return 中把 back1,back2的变化会保留下来 return func() int { temp := back1 back1, back2 = back2, (back1 + back2) //返回temp return temp } } func main() { f := fibonacci1() // for i := 0; i < 10; i++ { // 检测下前10个值 fmt.Println(f()) } } ``` ## 接口实现 ### 接口与隐式实现 无需声明某个结构体实现了接口,当结构体满足接口时,即完成了接口的实现 ``` type I interface { M() } type T struct { S string } // 此方法表示类型 T 实现了接口 I,但我们无需显式声明此事。 func (t T) M() { fmt.Println(t.S) } ``` ### 空接口( interface) - 指定了零个方法的接口值 创建符合接口的结构体 ``` //定义phone的接口必须要有call type Phone interface { call() } //构建结构体 type NokiaPhone struct { } func (nokiaPhone NokiaPhone) call() { fmt.Println("I am Nokia, I can call you!") } func main() { var phone Phone phone = new(NokiaPhone) //接头体传入接口 如果不存在call() 则new 会保存 phone.call() fmt.Println(reflect.TypeOf(phone)) } ``` ### interface 可以当任何值 ``` // 定义a为空接口 var a interface{} var i int = 5 s := "Hello world" // a可以存储任意类型的数值 a = i a = s ``` ### interface变量存储的类型 可以直接判断是否是该类型的变量:` value, ok = element.(T)`,这里value就是变量的值,ok是一个bool类型,element是interface变量,T是断言的类型。 ``` ype Element interface {} type List [] Element type Person struct { name string age int } func main() { list := make(List,3) list[0] = 1 // an int list[1] = "Hello" // a string list[2] = Person{"Dennis", 70} for index, element := range list { if value, ok := element.(int); ok { fmt.Printf("list[%d] is an int and its value is %d\n", index, value) } else if value, ok := element.(string); ok { fmt.Printf("list[%d] is a string and its value is %s\n", index, value) } else if value, ok := element.(Person); ok { fmt.Printf("list[%d] is a Person and its value is %s\n", index, value) } else { fmt.Printf("list[%d] is of a different type\n", index) } } } ``` ### 接口实现 io.Write ``` type ByteCounter int func (c *ByteCounter) Write(p []byte) (int, error) { *c += ByteCounter(len(p)) // convert int to ByteCounter return len(p), nil } func main() { var c ByteCounter fmt.Fprintf(&c, "hello, %s", "Dolly") fmt.Println(c) // "12", = len("hello, Dolly") } ``` ## Map类型(map) 1. 初始化并赋值 ``` var countryCapitalMap map[string]string /*创建集合 */ countryCapitalMap = make(map[string]string) ``` 等同于 ``` countryCapitalMap := make(map[string]string) ``` 2. 删除 ``` countryCapitalMap := make(map[string]string) countryCapitalMap [ "France" ] = "Paris" //删除 delete(countryCapitalMap, "France") ``` 3. 存在键判断键是否 ``` elem, ok = m[key] ``` ## 结构化类型(struct) 可比较的结构体可用于 map ``` type address struct { hostname string port int } hits := make(map[address]int) hits[address{"golang.org", 443}]++ ``` 在其他结构体中共享结构体 ``` type Point struct { X,Y int } type ColoredPoint struct { *Point Z int } p := Point{X: 1, Y: 2} point1 := ColoredPoint{&p,3} point2 := ColoredPoint{&p,4} p.X++ fmt.Printf("%+v\n", point1.X) // 2 fmt.Printf("%+v\n", point2.X) // 2 ``` ## 反射 ``` t := reflect.TypeOf(i) //得到类型的元数据,通过t我们能获取类型定义里面的所有元素 v := reflect.ValueOf(i) //得到实际的值,通过v我们获取存储在里面的值,还可以去改变值 ``` ## 类型断言 1. 使用 switch 断言 ``` var a interface{} a = 123.1 switch value := a.(type) { case int: fmt.Printf("int : %v", value) case float64: fmt.Printf("float : %v", value) case string: fmt.Printf("string : %v", value) case bool: fmt.Printf("bool : %v", value) default: fmt.Printf("not found") } ``` 2. 使用反射 (推荐) ``` a = 123.1 of := reflect.TypeOf(a) fmt.Println(of) //float64 ``` ## 特殊常量iota概念 1. iota在 const关键字出现时将被重置为0; 2. const中每新增一行常量声明将使iota计数一次; 3. iota常见使用法 ``` 1.跳值使用法 const ( C = iota //0 D = iota //1 _ E = iota //3 ) 2.插队使用法 const ( C=iota //0 D=iota //1 B="asd" E =iota //3 ) 3.表达式隐式使用法 const ( C=iota*2 //0 D //1*2=2 B //2*2=4 ) const ( _ = 1 << (10 * iota) KiB // 1024 MiB // 1048576 GiB // 1073741824 TiB // 1099511627776 (exceeds 1 << 32) PiB // 1125899906842624 EiB // 1152921504606846976 ZiB // 1180591620717411303424 (exceeds 1 << 64) YiB // 1208925819614629174706176 ) 4.单行使用法 const ( A,B=iota,iota*3 //A=0 B=0 C,D //C=1 D=3 ) ```