这是我参与「第三届青训营 -后端场」笔记创作活动的第2篇笔记
函数 一等公民
func div(a, b int) (q, r int) {
return a / b, a % b
}
- 函数返回多个值时可以起名字
- 仅用于非常简单的函数
- 对于调用者而言没有区别
函数式编程语言
函数的参数,返回值,函数体内都可以有函数
func apply(op func(int, int) int, a, b int) int {
p := reflect.ValueOf(op).Pointer()
opName := runtime.FuncForPC(p).Name() //拿到函数名
fmt.Printf("Calling function %s with args "+"(%d, %d)\n", opName, a, b)
return op(a, b)
}
func pow(a, b int) int {
return int(math.Pow(float64(a), float64(b)))
}
func main() {
fmt.Println(apply(pow, 3, 4))
//Calling function main.pow with args (3, 4) 81
}
可变参数列表
func sum(values ...int) int {
sum := 0
for i := range values {
sum += values[i]
}
return sum
}
func main() {
fmt.Println(sum(1,2,3,4,5)) //15
}
指针(重要)
- 指针不能运算
如果用var x int 声明一个变量x,那么&x(取x变量的内存地址)表达式将产生一个指向该整数变量的指针
指针对应的数据类型是*int
若指针名字为p,那么可以说“p指针指向变量x”,或者“p指针保存了x变量的内存地址”
x := 1
p := &x //p, of type *int ,points to x
fmt.Prinln(*p) //"1"
*p = 2 //equivalent to x = 2
fmt.Println(x) // "2"
参数传递
C++中
- 值传递 : 拷贝
- 引用传递: 不拷贝
Go中
Go语言中只有值传递(拷贝)一种方式
方法一:
func swap(a, b *int) {
*b, *a = *a, *b
}
func main() {
a, b := 3,4
swap(&a, &b)
fmt.Println(a, b) //4 3
}
方法二:
func swap(a, b int) (int, int) {
return b, a
}
func main() {
a, b := 3,4
swap(a, b)
fmt.Println(a, b) //4 3
}
数组Array
- 数量写在类型前
range的三种用法- 数组的遍历
package main
import "fmt"
func main() {
var arr1 [5]int
arr2 := [3]int{1, 3, 5} //需要告诉初值
arr3 := [...]int{2, 4, 6, 8, 10} //
var grid [4][5]int
fmt.Println(arr1, arr2, arr3)
fmt.Println(grid)
for i, v := range arr3 {
fmt.Println(i, v)
}
//for _, v := range arr3 {
//fmt.Println(v)
//}
}
为什么要用range?
- 意义明确美观,C++没有类似能力
- Java Python :只能for each value,不能同时获取i,v
- 除了数组,其他地方也会用到
- 在Go语言中一般不直接使用数组,而是使用切片
数组是值类型
- [10]int 和 [20]int 是不同类型
- 调用func f(arr [10]int) 会 拷贝 数组
func printArray(arr *[5]int) {
arr[0] = 100
for i, v := range arr {
fmt.Println(i, v)
}
}
func main() {
var arr1 [5]int
arr3 := [...]int{2,4,6,8,10}
fmt.Println("printArray(&arr1)")
printArray(&arr1)
fmt.Println("printArray(&arr3)")
printArray(&arr3)
fmt.Println("arr1 and arr3")
fmt.Println(arr1, arr3)
}
切片(Slice) 重要!
arr := [...]int {0,1,2,3,4,5,6,7}
s := arr[2,6] //2 3 4 5
s [0] = 10 //arr的值变为[0 1 10 3 4 5 6 7]
- Slice 本身没有数据,是对底层array的一个view
Slice 可以 Reslice
Slice的扩展
- Slice可以向后扩展,不可以向前扩展
- s[i] 不可以超越len(s), 向后扩展不可以超越底层数组cap(s)
package main
import "fmt"
func main() {
arr := [...]int {1,2,3,4,5,6,7}
s1 := arr[2:6]
s2 := s1[3:5]
fmt.Println("s1= ", s1) //s1 = [2 3 4 5]
fmt.Println("s2= ", s2) //s2 = [5 6]
}
Slice添加元素
- 添加元素时如果超越cap, 系统会重新分配更大的底层数组,原来的数组(可能会被垃圾回收掉)
- 由于值传递的关系,必须接受append的返回值
- s = append(s, val)
- s := make([]int, 16, 32) // len, cap
package main
import "fmt"
func printSlice(s []int) {
fmt.Printf("len=%d,cap=%d",len(s),cap(s))
}
func main(){
s1 := []int{2,4,6,8}
printSlice(s1)
s2 := make([]int, 16)
printSlice(s2)
s3 := make([]int, 10, 32)
printSlice(s3)
//len=4, cap=4
//len=16, cap=16
//len=10, cap=32
}
Slice复制元素
copy(destination,source)
Slice删除元素
s2 := []int{2,4,6,8,0,0,0,0,0,0,0}
fmt.Println("Deleting elements from slice") //delete 8
s2 = append(s2[:3],s2[4:]...)
fmt.Println("Popping from front")
front := s2[0]
s2 = s2[1:]
fmt.Println("Popping from back")
tail := s2[len(s2) -1]
s2 = s2[:len(s2) - 1]