Go_数据类型
字符串, 字符, 字节
字符串:
go语言中字符串用"双引号"或`反引号`(1左边那个键). 并且反引号还有取消转义的作用
package main import "fmt" func main(){ fmt.Println(`a\na`) // a\na fmt.Println("a\na") // a换行a }
字符串操作
// 字符串拼接 str3 := str1 + str2 // 格式化 package main import "fmt" func main(){ name := "自由" age := 18 var aa string aa = fmt.Sprintf("%s %d",name, age) fmt.Println(aa) }
字符串切片
package main import "fmt" func main(){ str1 := "hello word" str2 := str1[2:7] fmt.Println(str2) }
字符串的底层布局: 存放起始内存位置和长度的结构体
package main import "fmt" func main(){ str1 := "hello word" str2 := str1[2:7] fmt.Printf("%p %p", str1[2], str2[1]) // %!p(uint8=108) %!p(uint8=108) }
求长度: len(str) 不演示
byte, rune
byte 等同于int8,常用来处理ascii字符
rune 等同于int32,常用来处理unicode或utf-8字符
package main import ( "fmt" ) func main() { var str = "hello 你好" //golang中string底层是通过byte数组实现的,座椅直接求len 实际是在按字节长度计算 所以一个汉字占3个字节算了3个长度 fmt.Println("len(str):", len([]byte(str)),[]byte(str)) // len(str): 12 [104 101 108 108 111 32 228 189 160 229 165 189] fmt.Println("rune:", len([]rune(str)),[]rune(str) ) // rune: 8 [104 101 108 108 111 32 20320 22909] }
string和strconv工具类的使用
strings.HasPrefix(s string, prefix string ) bool; 判断字符串s是否以prefix开头 strings.HasSuffix(s string, suffix string ) bool; 判断字符串s是否以suffix结尾 strings.Index(s string, str string) int; 判断str在s中首次出现的位置,如果没有返回-1 strings.LastIndex(s string, str string) int; 判断str在s中最后出现的位置,如果没有返回-1 strings.Replace(str string, old string, new string, n int); 操作原始字符串替换,n为替换次数 strings.Count(str string, substr string) int; 字符串计数 strings.Repeat(str string, count int) string; 将str重复n次 strings.ToLower(str string) string; 转为小写 strings.ToUpper(str string) string; 转换为大写 strings.TrimSpace(str string) string; 去掉str首尾空白 strings.Trim(str string, cut string) string; 去掉字符串首尾cut字符 strings.TrimLeft(str string, cut string) string; 去掉str左面的cut字符 strings.TrimRight(str string, cut string) string; 去掉str右面的cut字符 strings.Fields(str string) []string ; 返回空格分割的字符串数组 strings.Split(str string, split string) []string ; 返回以split分割str的字符串数组 strings.Join(a []string, sep string) string; 用sep将a中的字符串连接起来 // 类型转换 -- 重点 strconv.Atoi(s string) (int, error); 将一个字符串转化成数字 strconv.Itoa(i int) string; 将一个数字转化成字符串
数字
int, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64
类型多多
bool类型
只能存在true和false(默认false)
相关操作符!(非),&&(与),||(或) .短路运算
数组与切片
数组 : 定长的存放相同数据类型的容器, 其中元素的内存是连续的
slice : 切片是数组的一个引用,因此切片是引用类型
但是切片的长度是会改变的, 当向他添加元素超出了他的容量时, 会重新分配内存
使用len(数组/切片)可以获得数组大小和slice中元素个数, cap(切片)可以获得切片的容量大小
数组相关操作
// 声明 // var a [len]type // 长度是数组类型的一部分. 因此,[5] int和[10]int是不同的类型 // 数组可以通过下标来访问, 赋值 // 数组是值传递, 赋值或传参都会产生副本 package main import "fmt" func main() { a := [5]int{1,2,3,4,5} fmt.Println(a) b := a fmt.Printf("%p %p",&a, &b) // 0x10c2a0a0 0x10c2a0e0 }
切片相关操作
// slice的初始化: make函数或者数组切片,数组的切片得到的是slice对象 // make()初始化 var a []int // 声明一个int类型的切片, 与数组的区别就是他不用指定长度 a = make([]int, 5) // 分配内存, 设置大小 // make方法 make([]type, len) make([]type, len, cap) //数组切片初始化 package main import "fmt" func main() { var a = [4]int{1,2,3,4} b:=a[:] fmt.Println(b) } // 添加值 package main import "fmt" func main() { a := make([]int, 5) b := append(a, 1) fmt.Println(a) // [0 0 0 0 0] fmt.Println(b) // [0 0 0 0 0 1] } // 分解添加 var a = []int{1,2,3} var b = []int{4,5,6} a = append(a, b…)
切片内部
当由数组得到切片时, 其实指向的是同一地址, 修改切片元素时, 列表也会被修改, 当长度变长后重新分配了内存, 再去修改,不会去改变数组
package main import "fmt" func main() { var a = [4]int{1,2,3,4} b:=a[:] b[0]=100 fmt.Println(a) // [100 2 3 4] fmt.Println(b) // [100 2 3 4] b = append(b,100) b[0] = 1 fmt.Println(a) // [100 2 3 4] fmt.Println(b) // [1 2 3 4 100] }
引用类型
切片属于引用类型(主要是因为其内部结构, 指向的是同一地址)
package main import "fmt" func main() { a := make([]int,5) fmt.Println(a) // [0 0 0 0 0] b := a fmt.Printf("%p %p\n",&a, &b) // 0x10b5c0c0 0x10b5c0f0 外部地址不同 a[0] = 1 fmt.Println(a) // [1 0 0 0 0] fmt.Println(b) // [1 0 0 0 0] }
拷贝, 赋值其内部指向的数组
copy(new_slice1, old_slice2)
排序 -- sort包
package main import ( "sort" // 该包 ) func main(){ // 整数类型排序 var a = [...]int{1,4,2,5} sort.Ints(a[:]) // 需要传递一个切片 // 字符串排序 var b = [...]string{"abc", "cba"} sort.Strings(b[:]) // 浮点数排序 var c = [...]float64{1.11, 2.11} sort.Float64s(c[:]) // 查找, 返回的是排序后的位置 index := sort.SearchInts(a[:], 2) }
指针
指针变量: 值存放的是内存地址, 可以通过该内存地址找到那个位置
指针变量声明
var 标识符 *type
ps: 通过类型可以判断所占内存长度和在内存中的存储方式, 在存取的那个位置向后移动固定长度便能得到该元素
在比较复杂一点的就是指向指针的指针 : var 标识符 **type
指针操作符
&(非指针变量) 取该变量的地址 *(指针变量) 取该变量的值/也可进行赋值操作,修改指针变量指向地址的值
非引用类型的变量可以通过传递指针的方式完成对原值的修改
package main import "fmt" func aa(int2 *int){ *int2 = 100 } func main() { var a = 10 aa(&a) fmt.Println(a) //100 }
map
键值存储的数据结构, 类似python的字典,不过要声明键值的类型
声明及初始化
//var map1 map[keytype]valuetype var a map[int]string var a map[string]map[string]string // key是string, value是map , 像这种嵌套结构的zhi也是需要make的 // 初始化 var a map[string]string make(a, 10) // 或 var a map[string]string = map[string]string{"key":"value"} // 接上面的那个嵌套结构 package main import "fmt" func main() { var a map[string]map[string]string a = make(map[string]map[string]string,10) a["wo"] = make(map[string]string,10) fmt.Println(a) // map[wo:map[]] a["wo"]["ni"] = "你谁啊" fmt.Println(a) // map[wo:map[ni:你谁啊]] }
map操作
// 赋值 var a map[string]string = map[string]string{“hello”: “world”} a[“hello”] = “world” // 取值 ok是bool值,可以通过ok来判断是否有值 Val, ok := a[“hello”] //遍历 for k, v := range a { fmt.Println(k,v) } // 删除 delete(a,"hello") // 长度 len(a)
channel
另说