在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
变量 go和java一样,是静态类型语言,变量有固定的数据类型,不能修改。 go用var定义变量,和java定义变量不同,go的变量类型需要放在变量名后面。 java:String str = "abc"; go:var str string = "abc" 当显式提供变量的初始值时,变量类型可以省略,编译器会自动推断。进一步,也可以省略var,此时等号前面要加个冒号: var str0 = "abc" str1 := "abc" 可以一次定义多个变量:var x, y int32 在一次定义多个变量时,变量类型也可以各不相同: var a, b = 100, "zhangsan" a, b := 100, "zhangsan" 局部变量未使用时,编译器会报错。全局变量没事。为了规避编译器对未使用的局部变量的检查,可以用_替代局部变量名。 常量 用const来定义常量。其他跟定义变量一样,只是const不能省略。 变量类型 bool,1个字节 int、uint,在32位平台是4个字节,在64位平台是8个字节 int8、uint8、byte(uint8的别称),1个字节。int8取值范围是[-27, 27-1],即[-128, 127]。uint8是无符号int8,取值范围是[0, 255]。 int16、uint16,2个字节。int16取值范围是[-215, 215-1],即[-32768, 32767]。 int32、uint32,4个字节。int32的别称是rune,取值范围是[-231, 231-1],即[-2147483648, 2147483647]。uint32是无符号的int32,取值范围是[0, 232-1]。 int64、uint64,8个字节 string 和java不同,go中的string是数据类型,而不是引用或者指针类型,而且零值是空字符串,不是nil。 string是只读的byte slice,和java不同,len()返回包含的byte数,而不是字符数。如len("a")返回1,len("ab")返回2,len("中")返回3,len("中国")返回6。想获取字符数,可以用utf8包中的RuneCountInString函数,utf8.RuneCountInString("中国")返回2。也可以用utf8包中的RuneCount函数,入参是个byte分片,可以有字符串转换得到,utf8.RuneCount("中国")返回2。 string和byte slice互转 var s = "abc我爱你" var bytes []byte = []byte(s) b := string(bytes) log.Info("b=" + b) 字符串操作常用有2个内置包:strings和strconv。 strings有很多处理字符串的方法,如字符串分割Split(会生成一个字符串切片),取子串索引Index,拼接字符串切片Join,字符串替换ReplaceAll,是否包含某子串Contains、转大小写ToUpper/ToLower。字符串截取没有对应的方法,需要通过str[2:5]的方式。根据正则替换的话,不像java中的string自带相应的replace方法,go在strings包中没有可以正则替换的方法,需要用到regexp。 strconv主要包含int和字符串互转的方法:Itoa(i int) string、Atoi(s string) (int, error),bool和字符串互转的方法:FormatBool(b bool) string、ParseBool(str string) (bool, error)。 strconv.Itoa(i int) string,整数转字符串。strconv.Atoi(s string) (int, error),字符串转整数,返回值有2个,第一个是整数,第二个是error。示例如下: func main() {
const (
a = 0
c = "1"
)
fmt.Println(strconv.Itoa(a))
cI, _ := strconv.Atoi(c)
fmt.Println(cI)
}
字符串拼接 1、如果有一个现成的字符串分片,则用strings包的Join函数最好。 2、其他情况下,用bytes包Buffer最好。 初始化buffer:var buffer bytes.Buffer 拼接:buffer.WriteString(s tring) 转字符串:buffer.String() 指针类型 表示方式是星号后面跟上其他类型,如*int、*string等,值为变量的内存地址。如 func main() { var a int = 10 var ptr *int = &a fmt.Println("ptr= ", ptr) fmt.Println("*ptr= ", *ptr) } *int表示int指针类型,值应该是一个int型变量的内存地址。同理,*string型指针变量的值应该是一个string型变量的内存地址。 &后面跟变量名,返回此变量指向的内存地址。*后面跟指针类型变量,返回此指针变量指向的值,即该内存地址对应的值。 数组 数组定义: 第一种方式: var b [3]int32 此时3个元素值都为0。可以一个一个赋值 b[0] = 1 b[1] = 2 b[2] = 3 第二种方式: a := [5]int32{} 此时5个元素值都为0 也可以直接在大括号中赋值: a := [5]int32{1, 2, 3, 4, 5} 中括号中的用于表示数组长度的数字可以由...代替,如 a := [...]int32{1, 2, 3, 4, 5} 第三种方式: a := [...]int32{5: 10} 这种方式表示的意思是,索引为5的元素值为10,5之前的索引的元素值都为0,数组长度为6。 go和java不一样,两个数组可以用==比较,如果两个数据长度一样,且对应索引处的元素一样,则==返回true,否则返回false。长度不同的两个数组用==比较,会报编译错误。 数组指针与指针数组 数组的指针 数组截取 取前三个:a[0:3],表示从索引0开始,到索引3结束,包括0,不包括3。也可以简写成a[:3] 取从索引3之后的元素:a[3:] 取全部:a[:] slice slice,分片,等同于java中的ArrayList,底层也是映射数组。 slice定义: 第一种方式: var s []int32 此时s等于nil,需要对s赋值,如s = []int32{},此时s变为一个capacity=0,length=0的slice 第二种方式: s := []string{"a", "b", "c"} 创建一个capacity=3,length=3,元素分别是"a"、"b"、"c"的slice 第三种方式: s := make([]string, 3) 创建一个length=3,capacity=3的slice,3个元素均是空字符串 s := make([]int32, 3, 5) 创建一个length=3,capacity=5的slice,3个元素均是0 用make的话,第一个参数是slice类型,注意不是元素类型,要带着中括号,第二个参数是长度length,第三个参数,假如有,表示容量capacity。如果只有两个参数,则capacity=length。 用len(s)可得到s的长度,用cap(s)可得到s的容量。 往分片中添加数据用append,一次可以放多个元素。s = append(s, 1, 2, 3) 和java中的list的add方法不同的是,append不会改变入参分片,append方法的返回值表示一个新切片,可以赋值给原来的分片,也可以赋值给别的变量。 append还可以用于合并两个分片,此时append的第二个参数要以三个点结尾,示例如下: func main() { s1 := []int{0, 1, 2, 3} s2 := []int{4, 5, 6, 7} s1 = append(s1, s2...) log.Println(s1) } slice截取同数组截取一样。 func main() { a := []string{"a", "b", "c"} b := a[0:2] b[0] = "A" fmt.Println(a) fmt.Println(b) b = append(b, "d") fmt.Println(a) fmt.Println(b) } 以上,对b切片某索引处赋值或者append一个元素后,会影响a切片,是因为b是从a截取所得,和a指向的是同一个数组。但是,如果append后b的capacity不够了,要扩容,这个时候b会指向一个新的数组,就不会影响slice a。 示例: a := []int{1, 2} b := append(a, 3) c := append(b, 4) d := append(b, 5) log.Println(a, b, c, d) c为什么是[1, 2, 3, 5],不应该是[1, 2, 3, 4]吗?原因是append不会改变入参slice。a一开始是len=2,capacity=2的切片,值依次是1、2。执行append(a, 3)并赋值给b,由于a对应的底层数组没有多余空间放3,所以只能开辟一块新的连续空间,即建一个新数组,长度为4,把a对应的数组的数据拷贝过来,索引依次是0、1,把3放在索引2的位置上。b指向新数组,a指向老数组。执行append(b, 4)并赋值给c,b对应的数组刚好还有一个空位,可以放4,c和b指向同一个数组,只不过b只包含数组前三个元素,而c包含数组的总共四个元素。执行append(b, 5)并赋值给d,b对应的数组虽然没有空位了,但是b只占数组前三个位置,所以会在数组的第4个位置放5,所以d、c和b现在都指向同一个数组了,b只包含数组前三个元素,依次是1、2、3,而d和c都是包含数组的全部元素,依次是1、2、3、4。 slice copy copy(dst []Type, src []Type),入参是两个slice,把后一个slice的内容复制到前一个slice中。这个copy函数很是个性,与其说是复制,不如说是替换。 场景一: 假如两个slice长度一样,则第一个slice的全部内容将会被第二个slice的内容替换。 场景二: 假如第一个slice的长度大于第二个slice的长度,比如说第一个slice长度为5,第二个slice长度为3,则第一个slice的前3个元素会被第二个slice的内容替换,后2个元素不变。 场景三: 假如第一个slice的长度小于第二个slice的长度,比如说第一个slice长度为3,第二个slice长度为5,则第一个slice的内容会被第二个slice的前3个元素替换。 slice排序 用sort包,如sort.Ints([]int),sort.strings([]string),这些都是正排。sort包没有提供可以直接倒序的方法,需要我们嵌套多个方法完成倒序的效果,示例如下:
如果分片中的元素是自定义类型,或者是map类型,那么该如何排序呢? contains remove
map map定义: 第一种方式: m := map[string]string{} // 创建一个空map m := map[string]int{"one": 1, "two": 2} // 创建一个包含两个键值对的map key的类型用中括号包裹,value的类型紧跟在key类型的后面。 第二种方式: m := make(map[string]string) m := make(map[int32]int32, 10) // 创建一个初始容量是10的map,10类似于java map的initialCapacity,此时m内部没有数据,len()还是返回0 make关键字既可以用于构造slice,也可用于构造map,但是不能用于构造数组。 map的put操作: m["one"] = 100 与java不同的是,在访问的key不存在时,会返回零值(字符串的话就是空字符串),而不会返回nil。那么如何实现java map的containsKey功能呢,我们可以把m["one"]赋值为两个变量,第二个变量如果为true,就表示map中有这个key,如果为false,则表示map中没有这个key。如下: one, ok := m["one"] map的delete操作:delete(map, key) 如delete(m, "one") map的遍历操作: 还是用for...range语法,只不过for...range的第一个参数是key,第二个参数是value。如下: for k, v := range m { value的类型除了常规的数字、字符串等类型外,还可以是个函数。如下: m := map[int]func(op int) int{} m的每个key分别对应不同的函数,通过key取出来直接可以用对应的函数。如果取一个不存在的key,则会返回函数的空值,函数空值是nil。可以直接用==判断一个变量是否是nil,如下: func main() { var m = map[int32]func(int32) int32{} m[1] = func(i int32) int32 { return i * i } f := m[-1] if f == nil { println("不存在") } else { println(f(2)) } } 变量名首字母大小写决定了其作用域。首字母大写的,可被包外引用,而小写则仅能在包内使用。 nil nil is a predeclared identifier representing the zero value for a pointer, channel, func, interface, map, or slice type. 在go中,string类型的值不可能是nil,只有指针类型、channel类型、函数类型、interface、map、分片的值才能是nil。 |
请发表评论