在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
1.什么是切片切片是由数组建立的一种方便、灵活且功能强大的包装(Wrapper)。切片本身不拥有任何数据。它们只是对现有数组的引用
2.切片的第一种方式:用数组创建一个切片// 切片定义的第一种方式:由数组切出来 var a [5]int= [5]int{1,2,3} // 切片是对数组的引用 var b []int=a[1:4] // 数组的切片没有步长 fmt.Println(b) //a[2] = 30 // 底层数组会影响切片 //fmt.Println(b) b[0] = 20 // 改变切片会影响底层数组 fmt.Println(a) 修改切片的值会影响到底层数组,并且修改底层数组也会影响到切片 切片的空值是nil类型 // 切片的空值是nil类型 var a[]int if a == nil{ fmt.Println("nil类型") } a[0] = 10 // 空值也不能赋值 fmt.Println(a)
3.切片的第二种方式:用make创建一个切片func make([]T,len,cap)[]T 通过传递类型,长度和容量来创建切片。容量是可选参数, 默认值为切片长度。make 函数创建一个数组,并返回引用该数组的切片。 // 第二种方式:直接定义,第一个数字是切片的大小,第二个数字是底层数组的长度,也就是切片的容量 var a[]int = make([]int,4,5) fmt.Println(a)
4.切片的长度(len)和容量(cap)切片追加值与查看长度和容量 // 切片的长度(len)和容量(cap) var a [5]int= [5]int{1,2,3,4,5} var b []int=a[1:4] // 切片追加值 b = append(b,999) // 长度加1,容量不变 fmt.Println(b) fmt.Println(a) // 底层数组也会跟着改变 fmt.Println(len(b)) // 长度4 fmt.Println(cap(b)) // 容量4 当切片追加超过容量的值时,会创建一个新的数组。现有数组的元素被复制到这个新数组中,并返回这个新数组的新切片引用。并且这个新切片的容量是原来切片的两倍 // 切片追加超过容量的值 b = append(b,888) fmt.Println(len(b)) // 长度5,超过了容量 fmt.Println(cap(b)) // 容量8,拷贝了原容量数组,并生成了一个原容量两倍的新数组 b[0] = 777 fmt.Println(b) fmt.Println(a) // 此时修改切片不会影响底层数组,他们间的关系断了,反之亦然,修改数组也不会英雄切片
5.切片的函数传递我们可以认为,切片在内部可由一个结构体类型表示。 切片的数据结构展示: type slice struct { Length int Capacity int ZerothElement *byte } 切片包含长度、容量和指向数组第零个元素的指针。当切片传递给函数时,即使它通过值传递,指针变量也将引用相同的底层数组。因此,当切片作为参数传递给函数时,函数内所做的更改也会在函数外可见。让我们写一个程序来检查这点。 // 切片的函数传递 a := make([]int,5) test(a) fmt.Println(a) test函数 func test(a []int) { a[0] = 999 fmt.Println(a) } 当我们在函数中修改切片的值时,外部的切片也会随之更改
6.多维切片类似于数组,切片可以有多个维度。 // 多维切片 var a[][]string = make([][]string,3) fmt.Println(a) // 长度为3的切片,有三个空值的切片元素 a[0] = make([]string,2) a[0][0] = "sxc" a[0][1] = "age" fmt.Println(a) // 长度为3的切片,并且第一个元素是一个长度为2的切片 循环多维数组 // 循环多维切片 var a = [][]string{{"sxc","cool"},{"zzj","dsb"}} //fmt.Println(a) for _,v := range a{ for _,v1 := range v{ // 循环两次 fmt.Println(v1) } }
7.切片的第三种方式:切片初始化时直接赋值// 第三种方式:切片初始化,直接赋值 var a[]int = []int{1,2,3} fmt.Println(a) fmt.Println(len(a)) // 长度为3 fmt.Println(cap(a)) // 容量也为3 多维数组初始化时直接赋值 // 多维切片初始化 var a[][]string = [][]string{{"sxc","cool"},{"zzj","dsb"}} fmt.Println(a) a[0][0] = "zzp" fmt.Println(a)
8.切片修改值只跟切片的长度有关,跟容量无关只能修改长度以内的切片 // 修改值只跟长度有关 var a[]int = []int{1,2} a[0] = 10 fmt.Println(a) //a[2] = 30 // 超过长度,不能修改 a = append(a, 30) a[2] = 50 fmt.Println(a) // 可以修改
9.内存优化切片持有对底层数组的引用。只要切片在内存中,数组就不能被垃圾回收。在内存管理方面,这是需要注意的。让我们假设我们有一个非常大的数组,我们只想处理它的一小部分。然后,我们由这个数组创建一个切片,并开始处理切片。这里需要重点注意的是,在切片引用时数组仍然存在内存中。 一种解决方法是使用 [copy] 函数 // 内存优化,copy函数 var a[]int = make([]int,3,10000) a[0] = 5 a[1] = 6 fmt.Println(a) //b:= make([]int,2,6) // 当长度少时,只取前几个 b:= make([]int,4,6) // 当长度多时,后面用0补充 copy(b, a) fmt.Println(b) 如上述切片,他的长度只有三,但是他引用的底层数组长度却有10000,此时使用该切片就十分耗费内存,我们可以使用copy函数来进行内存优化
二.可变参数函数可变参数函数是一种参数个数可变的函数。 语法: 如果函数最后一个参数被记作 请注意只有函数的最后一个参数才允许是可变的。 func main() { var a = []int{1,2,3,4} //test1(1,2,3,4) test1(a...) // 相当于打散 } func test1(a ...int) { fmt.Println(a) }
三.Map1.什么是mapmap 是在 Go 中将值(value)与键(key)关联的内置类型。通过相应的键可以获取到值。类似于python中的字典
2.如何创建map//语法 // map类型的key必须可hash var a map[key类型]value值类型 var a map[int]string fmt.Println(a) // map也是一个引用类型,空值也是nil
3.第一种创建方式:使用make初始化// map使用make初始化 var a = make(map[int]string) a[0] = "sxc" fmt.Println(a[0]) // 取不存在的值会返回value类型的空值 fmt.Println(a[1]) map的空值,就是value对应的类型的空值,比如int就是0 // 判断空值 if a[1]==""{ // 字符串的空值就是空字符串 fmt.Println("空值") } //可以使用该方法来判断是否为空值,因为每个类型的的空值的类型都是不一样的 if v,ok := a[1];ok{ fmt.Println(v) }else{ fmt.Println("空值") }
3.第二种创建方式:直接赋值// 初始化第二种方式,直接赋值 var a = map[int]string{0:"sxc",1:"zzj"} fmt.Println(a)
4.map删除值:delete方法删除 // map删除值,内置函数delete delete(a, 1) fmt.Println(a)
5.获取map的长度获取 map 的长度使用 [len]函数。 // map长度,len
fmt.Println(len(a))
6.map是引用类型和 [slices]类似,map 也是引用类型。当 map 被赋值为一个新变量的时候,它们指向同一个内部数据结构。因此,改变其中一个变量,就会影响到另一变量。 // map是引用类型,函数中修改也会影响
test5(a)
fmt.Println(a)
test函数中修改值,原值也会跟着改变 func test5(a map[int]string) { a[0] = "zzp" }
7.map的相等性map 之间不能使用 判断两个 map 是否相等的方法是遍历比较两个 map 中的每个元素。
8.扩展map是无序的,可以通过逻辑设计成有序的 m := make(map[int]string) var l []int m,l = add(1,"sxc", m, l) m,l = add(2,"zzj", m, l) m,l = add(3,"zzp", m, l) m,l = add(4,"lzx", m, l) m,l = add(5,"yzy", m, l) fmt.Println(m) fmt.Println(l) for _,v := range l{ fmt.Println(m[v]) } func add(b int, c string,m map[int]string,l []int) (map[int]string,[]int){ m[b] = c l = append(l,b) return m,l }
四.字符串1.什么是字符串Go 语言中的字符串是一个字节切片。把内容放在双引号""之间,我们可以创建一个字符串。让我们来看一个创建并打印字符串的简单示例。 package main import ( "fmt" ) func main() { name := "Hello World" fmt.Println(name) } Go 中的字符串是兼容 Unicode 编码的,并且使用 UTF-8 进行编码
2.字符串的字节数name := "hello 你好" fmt.Println(len(name)) // 统计字节数,12 上述代码中的name由5个英文字符(5*1共5个字节),一个空格(1个字节),两个中文字符组成(2*3共6个字符),故字节数是12 循环获取每个字节代码的十进制数字,都是unit8类型,也就是byte类型 // 字符串的循环,字符串是个只读切片 name := "hello你" for i:=0;i<len(name);i++{ fmt.Println(name[i]) fmt.Printf("%T",name[i]) // uint8也就是byte类型 fmt.Println() }
3.字符串的字符数name := "hello 你好" fmt.Println(utf8.RuneCountInString(name)) // 统计字符数 上述代码中的name一共由8个字符组成,故字符数是8 循环获取每个字符代码的十进制数字,都是int32类型,也就是rune类型 for _,v := range name{ fmt.Println(v) fmt.Printf("%T",v) // rune也就是int32类型 fmt.Println() fmt.Println(string(v)) }
4.字符串的长度[utf8 package] 包中的 package main import ( "fmt" "unicode/utf8" ) func length(s string) { fmt.Printf("length of %s is %d\n", s, utf8.RuneCountInString(s)) } func main() { word1 := "Señor" length(word1) word2 := "Pets" length(word2) } 上面程序的输出结果是: length of Señor is 5 length of Pets is 4 使用切片的方法拿值 fmt.Println(string(name[6])) // 只能拿字符的字节数对应的值,所以中文字符取不到
5.字符串是不可变的Go 中的字符串是不可变的。一旦一个字符串被创建,那么它将无法被修改。 package main import ( "fmt" ) func mutate(s string)string { s[0] = 'a'//any valid unicode character within single quote is a rune return s } func main() { h := "hello" fmt.Println(mutate(h)) } 在上面程序中的第 8 行,我们试图把这个字符串中的第一个字符修改为 'a'。由于字符串是不可变的,因此这个操作是非法的。所以程序抛出了一个错误 main.go:8: cannot assign to s[0]。 为了修改字符串,可以把字符串转化为一个 rune 切片。然后这个切片可以进行任何想要的改变,然后再转化为一个字符串。 package main import ( "fmt" ) func mutate(s []rune) string { s[0] = 'a' return string(s) } func main() { h := "hello" fmt.Println(mutate([]rune(h))) } 在上面程序的第 7 行,
五.指针1.什么是指针指针是一种存储变量内存地址(Memory Address)的变量。
如上图所示,变量
2.指针的声明(*+变量的类型)指针变量的类型为 *T,该指针指向一个 T 类型的变量。 package main import ( "fmt" ) func main() { b := 255 var a *int = &b fmt.Printf("Type of a is %T\n", a) fmt.Println("address of b is", a) } & 操作符用于获取变量的地址。上面程序的第 9 行我们把 Type of a is *int address of b is 0x1040a124
3.指针的零值指针的零值是nil package main import ( "fmt" ) func main() { a := 25 var b *int if b == nil { fmt.Println("b is", b) b = &a fmt.Println("b after initialization is", b) } } 上面的程序中, b is <nil> b after initialisation is 0x1040a124
4.指针的解引用,反解(*+变量)指针的解引用可以获取指针所指向的变量的值。将 package main import ( "fmt" ) func main() { b := 255 a := &b fmt.Println("address of b is", a) fmt.Println("value of b is", *a) } 在上面程序的第 10 行,我们将 address of b is 0x1040a124 value of b is 255 我们再编写一个程序,用指针来修改 b 的值。 package main import ( "fmt" ) func main() { b := 255 a := &b fmt.Println("address of b is", a) fmt.Println("value of b is", *a) *a++ fmt.Println("new value of b is", b) } 在上面程序的第 12 行中,我们把 address of b is 0x1040a124 value of b is 255 new value of b is 256
5.向函数传递指针参数package main import ( "fmt" ) func change(val *int) { *val = 55 } func main() { a := 58 fmt.Println("value of a before function call is",a) b := &a change(b) fmt.Println("value of a after function call is", a) } 在上面程序中的第 14 行,我们向函数 value of a before function call is 58 value of a after function call is 55
6.不要向函数传递数组的指针,而应该使用切片假如我们想要在函数内修改一个数组,并希望调用函数的地方也能得到修改后的数组,一种解决方案是把一个指向数组的指针传递给这个函数。 package main import ( "fmt" ) func modify(arr *[3]int) { (*arr)[0] = 90 } func main() { a := [3]int{89, 90, 91} modify(&a) fmt.Println(a) } 在上面程序的第 13 行中,我们将数组的地址传递给了 **a[x] 是 (*a)[x] 的简写形式,因此上面代码中的 (*arr)[0] 可以替换为 arr[0]**。下面我们用简写形式重写以上代码。 package main import ( "fmt" ) func modify(arr *[3]int) { arr[0] = 90 } func main() { a := [3]int{89, 90, 91} modify(&a) fmt.Println(a) } 该程序也会输出 这种方式向函数传递一个数组指针参数,并在函数内修改数组。尽管它是有效的,但却不是 Go 语言惯用的实现方式。我们最好使用切片来处理。 接下来我们用[切片]来重写之前的代码。 package main import ( "fmt" ) func modify(sls []int) { sls[0] = 90 } func main() { a := [3]int{89, 90, 91} modify(a[:]) fmt.Println(a) } 在上面程序的第 13 行,我们将一个切片传递给了
7.Go不支持指针运算Go 并不支持其他语言(例如 C)中的指针运算。 package main func main() { b := [...]int{109, 110, 111} p := &b p++ } 上面的程序会抛出编译错误:main.go:6: invalid operation: p++ (non-numeric type *[3]int)。 104 |
请发表评论