Go语言中函数,数组这些都是派生类型,也可以说是复杂类型,能够处理更加复杂的数据。
函数是基本的代码块,用于执行一个任务。
Go 语言最少有个 main() 函数。
函数声明告诉了编译器函数的名称,返回类型,和参数。
Go 语言标准库提供了多种可动用的内置的函数。例如,len() 函数可以接受不同类型参数并返回该类型的长度。如果我们传入的是字符串则返回字符串的长度,如果传入的是数组,则返回数组中包含的元素个数。
func function_name( [parameter list] ) [return_types] {
函数体
}
package main
import "fmt"
func main() {
fmt.Printf("函数类型为%T\n",sum)
fmt.Printf("函数值为%d\n",sum(1,2))
fmt.Printf("函数地址为%p",sum)
display()
}
func display() {
fmt.Println("这是一个无参数,也无返回值的函数")
}
func sum(a ,b int) int{
s:=a+b
fmt.Println("这是一个含有两个参数,返回一个int值的函数")
return s
}
结果为:
函数类型为func(int, int) int
这是一个含有两个参数,返回一个int值的函数
函数值为3
函数地址为0x498990
这是一个无参数,也无返回值的函数
数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,所以在GO中很少直接使用数组。
数组元素可以通过索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1,以此类推。
var name [SIZE] type
var arr[4] string//名为arr的长度为4的string型数组
var name [SIZE] type=[SIZE] type{...}
var s =[7]string{"Hello"," World"," Can ","you ","help ","me " ," ?"}
直接通过下标访问或者for,range遍历访问
//k为索引,v为元素值
for k,v:=range s{}
package main
import "fmt"
func main() {
var s =[7]string{"Hello"," World"," Can ","you ","help ","me " ," ?"}
//这里的[]里面如果不填,相当于另一种类型-----切片
//s:= [7]string{"Hello"," World"," Can ","you ","help ","me " ," ?"}
//var s[7]string
// s= [7]string{"Hello"," World"," Can ","you ","help ","me " ," ?"}
fmt.Printf("数组类型为%T\n",s)
fmt.Printf("数组地址为%p\n",s)
fmt.Printf("数组长度为%d\n",len(s))
fmt.Printf("数组第一位长度为%d\n",len(s[0]))
fmt.Println("数组为",s)
fmt.Println("循环访问数组:")
for i:=0;i<len(s);i++{
fmt.Print(" "+s[i])
}
fmt.Println("\nrange循环访问数组元素及其下标:")
for k,v:=range s{
fmt.Print(" K: ",k)
fmt.Print(" V: ",v)
}
}
数组类型为[7]string
数组地址为%!p([7]string=[Hello World Can you help me ?])
数组长度为7
数组第一位长度为5
数组为 [Hello World Can you help me ?]
循环访问数组:
Hello World Can you help me ?
range循环访问数组元素及其下标:
K: 0 V: Hello K: 1 V: World K: 2 V: Can K: 3 V: you K: 4 V: help K: 5 V: me K: 6 V: ?
数组可以有多维数组,如下二维数组
package main
import "fmt"
func main() {
var arr [3] [2]int= [3][2]int{{1,2},{2,3},{3,5}}
for _,v:=range arr{
fmt.Println("v的值为 ",v)
for _,s:=range v{
fmt.Print(" s的值为:",s)
}
fmt.Println()
}
}
v的值为 [1 2]
s的值为:1 s的值为:2
v的值为 [2 3]
s的值为:2 s的值为:3
v的值为 [3 5]
s的值为:3 s的值为:5
Go 语言切片是对数组的抽象。能增长的数组。
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
基本等同数组,只是不需要声明长度
var s[]string
s= []string{"Hello"," World"," Can ","you ","help ","me " ," ?"}
或者使用make函数make([]T, length, capacity)
,len是初始长度,capacity可选,指容量(容量不代表最大长度,只是声明一下)
s:=make([]string,3,10)
和数组一样,使用下标访问,也可以使用切片截取[start:end]
s:=[]string{"Hi ","My ","Friend ","!"}
fmt.Println("数组:",s)
//访问元素,slice [开始位置:结束位置]
fmt.Println("切片:",s[0:2])
//访问元素,类似数组
fmt.Println("切片:",s[0])
数组: [Hi My Friend !]
切片: [Hi My ]
切片: Hi
追加新元素使用 append 方法,追加元素,非原地操作,会生成新切片
package main
import "fmt"
func main() {
s:=[]string{"Hi ","My ","Friend ","!"}
fmt.Println("数组:",s)
//访问元素,slice [开始位置:结束位置]
fmt.Println("切片:",s[0:2])
//访问元素,类似数组
fmt.Println("切片:",s[0])
fmt.Println("切片后:",s)
fmt.Println("for---range遍历数组")
for _,v:=range s{
fmt.Print(" ",v)
}
fmt.Println("此时切片容量为",cap(s))
//追加元素,非原地操作,会生成新切片
fmt.Println("append方法追加元素: ",append(s, " yes"))
//追加多个元素
fmt.Println("append方法追加元素: ",append(s, " it's ","is ","good!"))
fmt.Println("此时切片容量为",cap(s))
n:=append(s, " it's ","is ","good!")
//当 s追加元素时,append(numbers, 2, 3, 4) 为什么 cap 从 4 变成 8 ?
//
//经过实践得知,append(list, [params]),先判断 list 的 cap 长度是否大于等于 len(list) + len([params]),
// 如果大于那么 cap 不变,否则 cap 等于 2*max{cap(list), cap[params]},所以当 append(s, 2, 3, 4) cap 从 2 变成 6。
fmt.Printf("此时切片容量为%d\n",cap(n))
fmt.Println("值是:",n)
}
数组: [Hi My Friend !]
切片: [Hi My ]
切片: Hi
切片后: [Hi My Friend !]
for---range遍历数组
Hi My Friend !此时切片容量为 4
append方法追加元素: [Hi My Friend ! yes]
append方法追加元素: [Hi My Friend ! it's is good!]
此时切片容量为 4
此时切片容量为8
值是: [Hi My Friend ! it's is good!]
切片在扩容时,容量的扩展规律是按容量的 2 倍数进行扩充,例如 1、2、4、8、16……,代码如下:
var numbers []intfor i := 0; i < 10; i++ { numbers = append(numbers, i) fmt.Printf("len: %d cap: %d pointer: %p\n", len(numbers), cap(numbers), numbers)}
代码输出如下:
len: 1 cap: 1 pointer: 0xc0420080e8
len: 2 cap: 2 pointer: 0xc042008150
len: 3 cap: 4 pointer: 0xc04200e320
len: 4 cap: 4 pointer: 0xc04200e320
len: 5 cap: 8 pointer: 0xc04200c200
len: 6 cap: 8 pointer: 0xc04200c200
len: 7 cap: 8 pointer: 0xc04200c200
len: 8 cap: 8 pointer: 0xc04200c200
len: 9 cap: 16 pointer: 0xc042074000
len: 10 cap: 16 pointer: 0xc042074000
代码说明如下:
往一个切片中不断添加元素的过程,类似于公司搬家,公司发展初期,资金紧张,人员很少,所以只需要很小的房间即可容纳所有的员工,随着业务的拓展和收入的增加就需要扩充工位,但是办公地的大小是固定的,无法改变,因此公司只能选择搬家,每次搬家就需要将所有的人员转移到新的办公点。
通过查看代码输出,可以发现一个有意思的规律:切片长度 len 并不等于切片的容量 cap。