网站备案查询 怎么弄,软件开发流程示意图,百度ai智能搜索引擎,哪里有网站开发定制一、数组
1.1 什么是数组 数组是一组数#xff1a;数组需要是相同类型的数据的集合#xff1b;数组是需要定义大小的#xff1b;数组一旦定义了大小是不可以改变的。
1.2 数组的声明
数组和其他变量定义没有什么区别#xff0c;唯一的就是这个是一组数#xff0c;需要给…一、数组
1.1 什么是数组 数组是一组数数组需要是相同类型的数据的集合数组是需要定义大小的数组一旦定义了大小是不可以改变的。
1.2 数组的声明
数组和其他变量定义没有什么区别唯一的就是这个是一组数需要给定一个大小比如[6] int[12] string。数组是一个相同类型数据的有序集合通过下标来取出对应的数据。数组有以下几个特点 长度必须是确定的如果不确定就不是数组大小不可以改变元素必须是相同类型不能是多个类型混合any 也是类型可以存放任意类型的数据数组中元素的类型可以是我们学的所有类型int、string、float、bool、array、slice、map长度不一样数组的类型就不一样
package main
import fmtfunc main() {// array数组定义变量// 数组也是一个数据类型// 数组的定义 [数组的大小size]变量的类型 // 我们定义了一组这个类型的数组集合大小为size最多可以保存size个数var arr1 [5]int// [0,0,0,0,0]// 给数组赋值,下标index所有的数组下标都是从0开始的。arr1[0] 100arr1[1] 200arr1[2] 300arr1[3] 400arr1[4] 500// 打印数组fmt.Println(arr1)// 取出数组中的某个元素fmt.Println(arr1[1])// 数组中的常用方法 len()获取数组的长度 cap() 获取数组的容量fmt.Println(数组的长度, len(arr1))fmt.Println(数组的容量, cap(arr1))// 修改数组的值index 1 代表的第二个数据了arr1[1] 10fmt.Println(arr1)fmt.Println(arr1[1])
}
1.3 初始化数组的几种方式
package main
import fmt// 数组的赋值初始化
func main() {// 在定义数组的时候就直接初始化var arr1 [5]int{1, 2, 3, 4, 5}fmt.Println(arr1)// 快速初始化 :arr2 : [5]int{1, 2, 3, 4, 5}fmt.Println(arr2)// 比较特殊的点// 数据如果来自用户我不知道用户给我多少个数据数组// ... 代表数组的长度// Go的编译器会自动根据数组的长度来给 ... 赋值自动推导长度// 注意点这里的数组不是无限长的也是固定的大小大小取决于数组元素个数。var arr3 [...]int{1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 8}fmt.Println(len(arr3))fmt.Println(arr3)// 数组默认值,我只想给其中的某几个index位置赋值。// {index:值}var arr4 [10]intarr4 [10]int{1: 100, 5: 500}fmt.Println(arr4) // [0 100 0 0 0 500 0 0 0 0]}
1.4 遍历数组元素
package mainimport fmt/*
1、直接通过下标获取元素 arr[index]2、 0-len i 可以使用for循环来结合数组下标进行遍历3、for range范围 (new)
*/
func main() {var arr1 [5]int{1, 2, 3, 4, 5}fmt.Println(arr1[0])fmt.Println(arr1[1])fmt.Println(arr1[2])fmt.Println(arr1[3])fmt.Println(arr1[4])// 错误index 5 out of bounds [0:5] 数组下标越界// 数组的长度只有5你要取出6个元素不可能取出//fmt.Println(arr1[5])fmt.Println(------------------)// 获取数组的长度 len()// 下标从0开始不能for i : 0; i len(arr1); i {fmt.Println(arr1[i])}fmt.Println(------------------)// goland 快捷方式 数组.for未来循环数组、切片很多时候都使用for range// for 下标,下标对应的值 range 目标数组切片// 就是将数组进行自动迭代。返回两个值 index、value// 注意点如果只接收一个值这个时候返回的是数组的下标// 注意点如果只接收两个值这个时候返回的是数组的下标和下标对应的值for _, value : range arr1 {fmt.Println(value)}}
1.5 数组是值类型
1.5.1 介绍 在 go 语言中数值是值类型。这意味着当你将一个数组赋值给另一个数组时go 会创建一个副本而不是引用同一块内存。这是与引用类型比如切片、slice、映射 map、通道 channel的区别之一。
package mainimport fmtfunc main() {arr1 : [3]int{1, 2, 3} // 创建一个数组arr2 : arr1 // 将 arr1 赋值给 arr2arr2[0] 100 // 修改 arr2 的第一个元素fmt.Println(arr1:, arr1) // 输出 arr1: [1 2 3]fmt.Println(arr2:, arr2) // 输出 arr2: [100 2 3]
} 在上面的例子中arr1 和 arr2 是两个独立的数组它们分别存储在不同的内存位置。当你修改 arr2 时arr1 不会受到影响因为它们是各自的副本。
1.5.2 为什么数组是值类型
数组在 Go 语言中具有固定的大小即数组的长度是类型的一部分这导致数组的值会在赋值时进行拷贝。赋值操作会复制整个数组的内容而不是传递数组的引用。
1.5.3 和切片的区别 切片slice是 Go 中的引用类型它并不存储数据本身而是引用底层数组。当你将一个切片赋值给另一个切片时它们共享底层数组的相同数据。
package mainimport fmtfunc main() {slice1 : []int{1, 2, 3} // 创建一个切片slice2 : slice1 // slice2 引用 slice1 底层的数组slice2[0] 100 // 修改 slice2 的第一个元素fmt.Println(slice1:, slice1) // 输出 slice1: [100 2 3]fmt.Println(slice2:, slice2) // 输出 slice2: [100 2 3]
} 在这个例子中修改 slice2 会影响 slice1因为它们共享相同的底层数组。 数组是值类型赋值时会复制整个数组的内容。切片是引用类型赋值时两个切片会共享相同的底层数组 1.6 数组的比较 在 go 语言中数组是可以直接进行比较的但是有一些限制。具体来说go 语言允许你比较两个数组是否相等只要他们的类型、长度和元素的值都相同。比较时会逐一比较数组的元素如果所有的元素都相同数组就视为相等。
1.6.1 允许比较
类型要求一致两个数组必须具有相同的类型包括相同的元素类型和相同的长度。逐个元素比较Go 会逐个元素进行比较如果数组的所有元素都相等则认为这两个数组相等。
package mainimport fmtfunc main() {arr1 : [3]int{1, 2, 3}arr2 : [3]int{1, 2, 3}arr3 : [3]int{3, 2, 1}arr4 : [4]int{1, 2, 3, 4}fmt.Println(arr1 arr2) // 输出: truefmt.Println(arr1 arr3) // 输出: falsefmt.Println(arr1 arr4) // 输出: 编译错误: 数组长度不同不能比较
}
arr1 arr2 返回 true因为它们的长度相同且每个元素的值都相同。arr1 arr3 返回 false因为数组的元素顺序不同。arr1 arr4 会导致编译错误因为这两个数组的长度不同Go 不允许直接比较长度不同的数组。
1.6.2 不允许比较
长度不同的数组如上面的 arr1 和 arr4它们的长度不同因此无法进行比较。切片不能直接比较切片是引用类型不能直接用 进行比较。如果需要比较切片的内容可以使用 reflect.DeepEqual 或者手动逐个比较切片元素。 切片不能直接使用 比较但你可以使用 reflect.DeepEqual 来比较切片内容。
package mainimport (fmtreflect
)func main() {slice1 : []int{1, 2, 3}slice2 : []int{1, 2, 3}slice3 : []int{3, 2, 1}fmt.Println(reflect.DeepEqual(slice1, slice2)) // 输出: truefmt.Println(reflect.DeepEqual(slice1, slice3)) // 输出: false
} 在 Go 语言中数组是可以直接比较的前提是数组的长度和元素类型必须相同。切片不能直接进行比较如果需要比较两个切片的内容可以使用 reflect.DeepEqual 函数。 二、切片
2.1 介绍 在 go 语言中切片是对数组的抽象。go 数组的长度是不可改变的在特定场景中这样的集合就不太适用go 中就提供了一种灵活、功能强悍的内置类型——切片动态数组。与数组相比切片的长度是不固定的可以追加元素在追加时可能使切片的容量增大。 切片是一种方便、灵活且强大的包装器切片本身没有任何数据他们只是对现有数组的引用。切片与数组相比不需要设定长度在 [ ] 中不用设定值相对来说比较自由。
从概念来说slice 像一个结构体这个结构体包含了三种元素
指针指向数组中 slice 指定的开始位置长度即 slice 的长度最大长度也就是 slice 开始位置到数组的最后位置的长度
package mainimport fmt// 定义切片
func main() {arr : [4]int{1, 2, 3, 4} // 定长fmt.Println(arr)var s1 []int // 变长长度是可变的fmt.Println(s1)// 切片的空判断初始的切片中默认是 nilif s1 nil {fmt.Println(切片是空的)}s2 : []int{1, 2, 3, 4} // 切片 变长fmt.Println(s2)fmt.Printf(%T,%T\n, arr, s2) // [4]int,[]intfmt.Println(s2[1])
}
2.2 切片的初始化 在 go 语言中切片slice可以通过几种不同的方式来初始化。这里总结了常见的几种方式
2.2.1 使用 make 函数 make 函数是 go 中用来创建切片的标准方式可以指定切片的长度和容量。
slice : make([]int, 5) // 创建一个长度为 5 的切片初始值为零值 [0, 0, 0, 0, 0] 可以指定切片的长度和容量如果只指定长度容量默认为长度如果指定了容量切片的容量就会扩展到指定的大小。
slice : make([]int, 5, 10) // 创建一个长度为 5容量为 10 的切片
2.2.2 通过字面量初始化 切片也可以通过字面量literal来初始化直接给出一个初始值。这种方式不需要明确指定长度Go 会根据提供的元素自动计算出长度。
slice : []int{1, 2, 3, 4, 5} // 创建并初始化一个切片
2.2.3 通过 nil 初始化默认值 当切片没有显式初始化时它默认是 nil它的长度和容量都是 0。
var slice []int // 创建一个 nil 切片长度和容量为 0
fmt.Println(slice nil) // 输出: true
2.2.4 通过数组创建切片
你也可以从一个数组中创建切片利用数组的部分或全部元素。
arr : [5]int{1, 2, 3, 4, 5}
slice : arr[1:4] // 创建一个切片包含 arr 数组的第二到第四个元素 [2, 3, 4] 在这里切片 slice 是从数组 arr 中的一部分创建的切片的长度和容量是基于数组的子集来决定的。
2.2.5 通过 copy 函数拷贝切片
通过 copy 函数你可以从一个已有的切片创建一个新的切片。
slice1 : []int{1, 2, 3, 4, 5}
slice2 : make([]int, len(slice1))
copy(slice2, slice1) // 将 slice1 的内容拷贝到 slice22.2.6 通过扩容创建切片
如果切片的容量不足以容纳新的元素可以通过 append 函数来动态扩容切片。
slice : []int{1, 2}
slice append(slice, 3, 4) // 在原切片基础上追加元素make 函数可以创建指定长度和容量的切片。字面量初始化直接使用 []type{} 创建并初始化切片。nil 初始化默认情况下未显式初始化的切片为 nil长度和容量为 0。从数组创建切片可以通过数组的部分或全部元素创建切片。copy 函数可以从现有的切片复制内容到新的切片。append 函数可以通过动态扩展切片的容量来添加元素。 2.3 切片的数据访问
2.3.1 切片的基础数据访问 切片的元素可以通过索引进行访问索引从 0 开始类似于数组。在切片中访问超出范围的索引会引发 panic 错误。
package mainimport fmtfunc main() {// 初始化一个切片slice : []int{10, 20, 30, 40, 50}// 通过索引访问切片元素fmt.Println(slice[0]) // 输出: 10fmt.Println(slice[2]) // 输出: 30// 修改切片中的元素slice[1] 100fmt.Println(slice) // 输出: [10 100 30 40 50]// 访问越界的索引会导致 panic// fmt.Println(slice[10]) // 运行时错误: panic: runtime error: index out of range
}2.3.2 切片的切片操作
Go 的切片支持通过 slice[low:high] 语法进行切片操作生成一个新的切片。这个操作包括
低索引low指定切片的起始位置包括该位置默认是 0。高索引high指定切片的结束位置不包括该位置。容量新切片的容量是原切片从 low 到末尾的部分。 [start, end] 如果只有 start 没有 end就表示从 start 开始到结尾的所有数据如果没有 start 有 end表示从0到 end 之前的所有数据如果有 start 没有 end表示从 start 开始到结尾的所有数据如果有 start 有 end表示全部数据 package mainimport fmtfunc main() {// 初始化一个切片slice : []int{10, 20, 30, 40, 50}// 获取从索引 1 到 3不包括 3部分的切片subSlice : slice[1:3] fmt.Println(subSlice) // 输出: [20 30]// 如果不指定低索引则默认从 0 开始subSlice2 : slice[:3] fmt.Println(subSlice2) // 输出: [10 20 30]// 如果不指定高索引则默认到切片的末尾subSlice3 : slice[2:] fmt.Println(subSlice3) // 输出: [30 40 50]// 获取完整的切片fullSlice : slice[:] fmt.Println(fullSlice) // 输出: [10 20 30 40 50]
}2.3.3 切片的容量和长度
长度Lengthlen(slice) 返回切片的长度即当前切片中元素的个数。容量Capacitycap(slice) 返回切片的容量即切片在当前数组中的总容量。容量通常是切片分配的底层数组大小。
package mainimport fmtfunc main() {slice : []int{10, 20, 30, 40, 50}fmt.Println(Length:, len(slice)) // 输出: Length: 5fmt.Println(Capacity:, cap(slice)) // 输出: Capacity: 5// 扩展切片slice append(slice, 60)fmt.Println(New Length:, len(slice)) // 输出: New Length: 6fmt.Println(New Capacity:, cap(slice)) // 输出: New Capacity: 10
}2.3.4 使用 append 添加元素 append 是 Go 切片的一个内建函数它用于向切片末尾添加元素并且在需要时自动扩容。如果追加的数据超过切片的容量Go 会创建一个新的底层数组并将原数据和新数据复制过去。
package mainimport fmtfunc main() {slice : []int{10, 20, 30}// 向切片添加单个元素slice append(slice, 40)fmt.Println(slice) // 输出: [10 20 30 40]// 向切片添加多个元素slice append(slice, 50, 60)fmt.Println(slice) // 输出: [10 20 30 40 50 60]// 向切片添加一个切片slice2 : []int{70, 80}slice append(slice, slice2...)fmt.Println(slice) // 输出: [10 20 30 40 50 60 70 80]
}2.3.5 切片的复制 切片可以通过 copy 函数将一个切片的内容复制到另一个切片中。需要注意copy 会复制源切片的元素到目标切片但目标切片的长度不一定和源切片一样大复制的元素数量会受到目标切片长度的限制。
package mainimport fmtfunc main() {slice1 : []int{10, 20, 30, 40, 50}slice2 : make([]int, 3)// 将 slice1 的前 3 个元素复制到 slice2copy(slice2, slice1)fmt.Println(slice2) // 输出: [10 20 30]// 如果目标切片更大剩余的元素保持零值slice3 : make([]int, 7)copy(slice3, slice1)fmt.Println(slice3) // 输出: [10 20 30 40 50 0 0]
}2.3.6 使用 for 进行遍历
package mainimport fmtfunc main() {s1 : make([]int, 0, 5)fmt.Println(s1)// 切片扩容append()s1 append(s1, 1, 2)fmt.Println(s1)// 问题容量只有5个那能放超过5个的吗 可以切片是会自动扩容的。s1 append(s1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7)fmt.Println(s1)// 切片扩容之引入另一个切片。// new 解构 slice.. 解出这个切片中的所有元素。s2 : []int{100, 200, 300, 400}// slice append(slice, anotherSlice...)// ... 可变参数 ...xxx// [...] 根据长度变化数组的大小定义// anotherSlice... , slice...解构可以直接获取到slice中的所有元素// s2... {100,200,300,400}s1 append(s1, s2...)// 遍历切片for i : 0; i len(s1); i {fmt.Println(s1[i])}for i : range s1 {fmt.Println(s1[i])}
}
2.4 切片的元素删除 在 Go 语言中切片本身不提供直接删除元素的方法但是可以通过切片的切片操作和 append 函数来间接实现删除元素的功能。
2.4.1 删除切片中的元素 如果你需要删除切片中的某个元素比如删除指定位置的元素可以通过以下两种方法来完成
通过切片拼接你可以使用 append 函数和切片的切片操作将切片分为两部分排除要删除的元素然后重新拼接这两部分。
package mainimport fmtfunc main() {// 初始化一个切片slice : []int{10, 20, 30, 40, 50}// 打印原始切片fmt.Println(Original Slice:, slice)// 删除索引为 2 的元素即元素 30i : 2slice append(slice[:i], slice[i1:]...)// 打印修改后的切片fmt.Println(Modified Slice:, slice)
}2.4.2 删除多个元素 如果你需要删除多个元素可以按照相同的方式通过切片拼接来删除多个索引的元素。你只需进行多个切片操作。
package mainimport fmtfunc main() {// 初始化一个切片slice : []int{10, 20, 30, 40, 50}// 打印原始切片fmt.Println(Original Slice:, slice)// 删除索引为 1 和 3 的元素slice append(slice[:1], slice[2:3]...)slice append(slice[:2], slice[3:]...)// 打印修改后的切片fmt.Println(Modified Slice:, slice)
}2.4.3 删除切片中的特定元素值
如果你要删除某个具体的元素值而不是指定索引可以遍历切片并删除所有匹配的元素。
package mainimport fmtfunc main() {// 初始化一个切片slice : []int{10, 20, 30, 40, 30, 50}// 打印原始切片fmt.Println(Original Slice:, slice)// 删除值为 30 的所有元素target : 30newSlice : []int{}for _, v : range slice {if v ! target {newSlice append(newSlice, v)}}// 打印修改后的切片fmt.Println(Modified Slice:, newSlice)
}删除指定索引的元素通过切片操作和 append 来拼接删除元素前后的部分。删除多个元素通过多次拼接来删除多个索引的元素。删除指定值的元素遍历切片并将不匹配的元素添加到新的切片中。 2.5 切片的底层原理
2.5.1 为什么要理解切片的底层原理 go 中的 slice 在函数参数传递的时候是值传递还是引用传递值传递效果上呈现出了引用的效果不完全是。 切片本身是引用类型 切片包含三个部分指向底层数组的指针、切片的长度和切片的容量。切片本身并不存储数据而是通过指针指向底层的数组。因此切片的元素存储在底层数组中而切片本身是一个结构体包含了这个数组的一个视图。 切片作为函数参数传递时 当切片作为参数传递给函数时传递的是 切片的引用即切片指向底层数组的指针。这样在函数内部对切片的修改会影响原始切片。然而切片本身的结构例如切片的长度、容量是可以在函数中修改的但这不会改变传递到函数中的切片的原始引用。也就是说如果函数修改了切片的长度或容量这些变化不会影响原始切片的长度和容量。
package mainimport fmtfunc modifySlice(s []int) {// 修改切片的内容s[0] 99
}func main() {slice : []int{1, 2, 3, 4}fmt.Println(Before:, slice)modifySlice(slice)fmt.Println(After:, slice) // 由于切片是引用类型内容会被修改
}Before: [1 2 3 4]
After: [99 2 3 4]但是如果我们修改切片的长度则情况会有所不同
package mainimport fmtfunc modifySliceLength(s []int) {s append(s, 5) // 改变切片的长度fmt.Println(Inside function:, s)
}func main() {slice : []int{1, 2, 3}fmt.Println(Before:, slice)modifySliceLength(slice)fmt.Println(After:, slice) // 原始切片的长度没有变化
}Before: [1 2 3]
Inside function: [1 2 3 5]
After: [1 2 3]在这个例子中modifySliceLength 函数通过 append 操作改变了切片的长度。虽然在函数内部切片的长度和内容都发生了变化但由于 append 操作可能导致切片重新分配底层数组函数外部的原始切片 slice 的长度并没有改变。 切片是引用类型因此传递给函数时是 引用传递修改切片的内容会影响原始切片。切片的 长度 和 容量 是在切片的结构体中存储的函数内对它们的修改不会影响原始切片除非通过重新赋值或 append 等操作导致切片重新分配新的底层数组。 2.5.2 切片的底层原理 在 Go 语言中切片slice是一个非常重要的类型它提供了一种灵活的方式来操作数组的部分内容。切片本身是对数组的一个抽象它具有一些非常重要的特性。为了理解切片的底层原理我们需要了解切片的内部结构及其与底层数组的关系。
2.5.2.1 切片的结构
切片本质上是一个结构体包含以下三个部分 指向底层数组的指针ptr 切片内部有一个指针指向底层的数组。这使得切片可以动态地调整大小而不需要重新分配数组。 切片的长度len 这是切片中元素的数量表示当前切片中包含的元素个数。 切片的容量cap 切片的容量表示从切片的开始位置到底层数组的末尾可用的元素数量。容量决定了切片在不重新分配的情况下最多可以容纳多少个元素。
2.5.2.2 切片与底层数组的关系 切片是对底层数组的一部分的引用它并不直接存储数据。切片通过指针指向底层数组的一段区间切片的长度和容量是基于该区间确定的。
切片的指针切片指向底层数组的某个位置不是从数组的开头开始可能是中间的某个位置。切片的长度切片当前使用的元素数量。切片的容量从切片的起始位置到底层数组末尾的元素数量。
2.5.2.3 切片的底层存储 当切片是通过数组或其他切片创建时它会直接指向底层数组底层数组是存储实际数据的地方。切片的大小即元素个数是可以调整的但它们共享同一个底层数组。 例如创建一个切片时Go 会根据你提供的长度和容量分配底层数组。如果你通过切片扩展例如使用 append使得切片的容量不足Go 会分配一个新的更大的数组并将数据复制到新数组中。
2.5.2.4 切片的扩容 当我们使用 append 函数向切片添加元素时Go 会检查切片的容量。如果当前容量足够append 会在原有的数组上直接增加元素如果容量不够Go 会分配一个新的更大的数组复制原始数组的内容并将新元素加入。
2.5.2.5 扩容策略 Go 使用一个增长的策略来扩展切片的容量。通常情况下当切片容量不足时Go 会将容量加倍或者增长 1.25 倍左右。这种扩容策略使得 append 操作的平均时间复杂度为 O(1)即使在多次调用中切片的扩容操作不会每次都需要重新分配和复制大量数据。 切片是一个包含指向底层数组的指针、长度和容量的结构体。切片本身并不包含数据而是对数组的一个视图它提供了对底层数组的引用。切片的容量决定了它能够容纳的最大元素数量超过容量时Go 会扩容底层数组。切片是一个非常灵活且高效的数据结构广泛用于Go的标准库和用户的应用程序中。 2.5.2.6 扩容的内存分析
每个切片引用了一个底层的数组切片本身不存储任何数据都是底层的数组来存储的所以修改了切片也就是修改了这个数组中的数据向切片中添加数据的时候如果没有超过容量直接添加如果超过了这个容量就会自动扩容成倍的增加 copy切片一旦扩容就是重新指向一个新的底层数组。
package mainimport fmt// 切片扩容的内存分析
// 结论
// 1、每个切片引用了一个底层的数组
// 2、切片本身不存储任何数据都是底层的数组来存储的所以修改了切片也就是修改了这个数组中的数据
// 3、向切片中添加数据的时候如果没有超过容量直接添加如果超过了这个容量就会自动扩容成倍的增加 copy
// - 分析程序的原理
// - 看源码
//
// 4、切片一旦扩容就是重新指向一个新的底层数组。
func main() {// 1、cap 是每次成倍增加的// 2、只要容量扩容了地址就会发生变化s1 : []int{1, 2, 3}fmt.Println(s1)fmt.Printf(len:%d,cap:%d\n, len(s1), cap(s1)) // len:3,cap:3fmt.Printf(%p\n, s1) // 0xc000016108s1 append(s1, 4, 5)fmt.Printf(len:%d,cap:%d\n, len(s1), cap(s1)) // len:5,cap:6fmt.Printf(%p\n, s1) // 0xc000010390s1 append(s1, 6, 7, 8)fmt.Printf(len:%d,cap:%d\n, len(s1), cap(s1)) // len:8,cap:12fmt.Printf(%p\n, s1) // 0xc00005e060s1 append(s1, 9, 10)fmt.Printf(len:%d,cap:%d\n, len(s1), cap(s1)) // len:10,cap:12fmt.Printf(%p\n, s1) // 0xc00005e060s1 append(s1, 11, 12, 13, 14)fmt.Printf(len:%d,cap:%d\n, len(s1), cap(s1)) // len:14,cap:24fmt.Printf(%p\n, s1) // 0xc00010c000
}
2.6 深拷贝、浅拷贝
深拷贝拷贝是数据的本身
值类型的数据默认都是深拷贝array、int、float、string、bool、struct....
浅拷贝拷贝是数据的地址会导致多个变量指向同一块内存。
引用类型的数据 slice、map因为切片是引用类的数据直接拷贝的是这个地址
切片如何实现深拷贝
package mainimport fmt// 切片实现深拷贝
func main() {// 将原来切片中的数据拷贝到新切片中s1 : []int{1, 2, 3, 4}s2 : make([]int, 0) // len:0 cap:0for i : 0; i len(s1); i {s2 append(s2, s1[i])}fmt.Println(s1)fmt.Println(s2)s1[0] 100fmt.Println(s1)fmt.Println(s2)
}
2.7 函数中参数传递问题 按照数据的存储特点来分
值类型的数据操作的是数据本身、int 、string、bool、float64、array...引用类型的数据操作的是数据的地址 slice、map、channal....
package mainimport fmtfunc main() {arr1 : [4]int{1, 2, 3, 4}fmt.Println(arr1:, arr1)update(arr1)fmt.Println(end arr1:, arr1)s1 : []int{1, 2, 3, 4}fmt.Println(s1:, s1)update2(s1)fmt.Println(end s1:, s1)
}// 函数补充在使用函数的时候一定要特别注意参数问题如果是值类型的很多传递是无效的。
// 一些值传递的类型的参数如果我们想通过函数来进行修改对应的值这个时候就需要使用指针// 指针变量 - 指向原来变量的地址// 数组是值类型的
func update(arr [4]int) {fmt.Println(-- arr:, arr)arr[0] 100fmt.Println(-- end arr:, arr)
}// 切片是引用类型的
func update2(s []int) {fmt.Println(-- s:, s)s[0] 100fmt.Println(-- end s:, s)
} 文章转载自: http://www.morning.wcgcm.cn.gov.cn.wcgcm.cn http://www.morning.horihe.com.gov.cn.horihe.com http://www.morning.zqfz.cn.gov.cn.zqfz.cn http://www.morning.qgxnw.cn.gov.cn.qgxnw.cn http://www.morning.rszt.cn.gov.cn.rszt.cn http://www.morning.fyxr.cn.gov.cn.fyxr.cn http://www.morning.hkpyp.cn.gov.cn.hkpyp.cn http://www.morning.dodoking.cn.gov.cn.dodoking.cn http://www.morning.wgxtz.cn.gov.cn.wgxtz.cn http://www.morning.mxftp.com.gov.cn.mxftp.com http://www.morning.zqcdl.cn.gov.cn.zqcdl.cn http://www.morning.wwdlg.cn.gov.cn.wwdlg.cn http://www.morning.pkrtz.cn.gov.cn.pkrtz.cn http://www.morning.nfpkx.cn.gov.cn.nfpkx.cn http://www.morning.sbczr.cn.gov.cn.sbczr.cn http://www.morning.cnqwn.cn.gov.cn.cnqwn.cn http://www.morning.pcgjj.cn.gov.cn.pcgjj.cn http://www.morning.mlcwl.cn.gov.cn.mlcwl.cn http://www.morning.cjxqx.cn.gov.cn.cjxqx.cn http://www.morning.xoaz.cn.gov.cn.xoaz.cn http://www.morning.rhpy.cn.gov.cn.rhpy.cn http://www.morning.qlxgc.cn.gov.cn.qlxgc.cn http://www.morning.wtcyz.cn.gov.cn.wtcyz.cn http://www.morning.smmrm.cn.gov.cn.smmrm.cn http://www.morning.msfqt.cn.gov.cn.msfqt.cn http://www.morning.gcjhh.cn.gov.cn.gcjhh.cn http://www.morning.jwgmx.cn.gov.cn.jwgmx.cn http://www.morning.pmlgr.cn.gov.cn.pmlgr.cn http://www.morning.hjwkq.cn.gov.cn.hjwkq.cn http://www.morning.hwxxh.cn.gov.cn.hwxxh.cn http://www.morning.pqsys.cn.gov.cn.pqsys.cn http://www.morning.elbae.cn.gov.cn.elbae.cn http://www.morning.xplng.cn.gov.cn.xplng.cn http://www.morning.bpmnj.cn.gov.cn.bpmnj.cn http://www.morning.xsgxp.cn.gov.cn.xsgxp.cn http://www.morning.qshxh.cn.gov.cn.qshxh.cn http://www.morning.nykzl.cn.gov.cn.nykzl.cn http://www.morning.prhqn.cn.gov.cn.prhqn.cn http://www.morning.rqqlp.cn.gov.cn.rqqlp.cn http://www.morning.qrcsb.cn.gov.cn.qrcsb.cn http://www.morning.hqrr.cn.gov.cn.hqrr.cn http://www.morning.rhjsx.cn.gov.cn.rhjsx.cn http://www.morning.tkgjl.cn.gov.cn.tkgjl.cn http://www.morning.lwrks.cn.gov.cn.lwrks.cn http://www.morning.mhwtq.cn.gov.cn.mhwtq.cn http://www.morning.mnwmj.cn.gov.cn.mnwmj.cn http://www.morning.tpqzs.cn.gov.cn.tpqzs.cn http://www.morning.ypcd.cn.gov.cn.ypcd.cn http://www.morning.1000sh.com.gov.cn.1000sh.com http://www.morning.tgwfn.cn.gov.cn.tgwfn.cn http://www.morning.clnmf.cn.gov.cn.clnmf.cn http://www.morning.kclkb.cn.gov.cn.kclkb.cn http://www.morning.fyzsq.cn.gov.cn.fyzsq.cn http://www.morning.wmglg.cn.gov.cn.wmglg.cn http://www.morning.zlhbg.cn.gov.cn.zlhbg.cn http://www.morning.qwrb.cn.gov.cn.qwrb.cn http://www.morning.xlztn.cn.gov.cn.xlztn.cn http://www.morning.jjzrh.cn.gov.cn.jjzrh.cn http://www.morning.qxnlc.cn.gov.cn.qxnlc.cn http://www.morning.cfhwn.cn.gov.cn.cfhwn.cn http://www.morning.gjqgz.cn.gov.cn.gjqgz.cn http://www.morning.rnpt.cn.gov.cn.rnpt.cn http://www.morning.ns3nt8.cn.gov.cn.ns3nt8.cn http://www.morning.gskzy.cn.gov.cn.gskzy.cn http://www.morning.jcnmy.cn.gov.cn.jcnmy.cn http://www.morning.hsrch.cn.gov.cn.hsrch.cn http://www.morning.thzwj.cn.gov.cn.thzwj.cn http://www.morning.dqwkm.cn.gov.cn.dqwkm.cn http://www.morning.jzmqk.cn.gov.cn.jzmqk.cn http://www.morning.cwcdr.cn.gov.cn.cwcdr.cn http://www.morning.knjj.cn.gov.cn.knjj.cn http://www.morning.cznsq.cn.gov.cn.cznsq.cn http://www.morning.wxckm.cn.gov.cn.wxckm.cn http://www.morning.jnzfs.cn.gov.cn.jnzfs.cn http://www.morning.lmfmd.cn.gov.cn.lmfmd.cn http://www.morning.ybshj.cn.gov.cn.ybshj.cn http://www.morning.ztfzm.cn.gov.cn.ztfzm.cn http://www.morning.jtfcd.cn.gov.cn.jtfcd.cn http://www.morning.sjjq.cn.gov.cn.sjjq.cn http://www.morning.jqpyq.cn.gov.cn.jqpyq.cn