指针类型
普通类型,变量量存的就是值,也叫值类型。指针类型存的是地址
获取变量量的地址, 用&, 比如: var a int, 获取a的地址:&a
指针类型,变量量存的是一个地址,这个地址存的才是值
获取指针类型所指向的值,使用:*, 比如:var *p int, 使用*p获取p指向的值

package main import( "fmt" ) func test1() { var a int a = 10 fmt.Println(a) var b *int fmt.Printf("%p ", &b) //指针这个变量的内存地址 fmt.Printf("%p ", b) //指针的内存地址 fmt.Printf("%p ", a) //常量 fmt.Printf("%p ", &a) //常量的内存地址 b = &a //将常量的内存地址指向指针 fmt.Printf("%d ", *b) *b = 100 //改变指针内存对应的值 fmt.Printf("a=%d ", a) } func modify(a *int) { *a = 100 } func test2() { var b int = 1 var p *int p = &b modify(p) fmt.Println(b) } func test3() { //p 默认初始化nil //指针的初始化 var p *int var b int p = &b *p = 200 //b = 200 fmt.Printf("%p %p %p ", p, &b, &p) //指针的初始化 p = new(int) *p = 1000 fmt.Printf("%d ", *p) fmt.Printf("%p %p %p ", p, &b, &p) //指针类型的变量初始化:1. 使用其他变量地址给它赋值。 2. 使用new分配。 } func test4(){ var p *string //1. 第一种方式 使用new分配。 p = new(string) *p = "abc" fmt.Println(*p) //2. 第二种方式 使用其他变量地址给它赋值。 var str string = "hello word" p = &str fmt.Println(*p) } func test5(){ //make和new的区别 var a []int a = make([]int, 10) a[0] = 100 fmt.Println(a) var p *[]int p = new([]int) //给指针分配内存地址 (*p) = make([]int, 10) //初始化切片 (*p)[0] = 100 fmt.Println(p) p = &a (*p)[0] = 1000 fmt.Println(a) } func modify_arr(a []int) { fmt.Printf("modify:%p ", a) a[0] = 100 //改变数据的的值 } func test6() { var a[6]int fmt.Printf("test6:%p ", &a) modify_arr(a[:]) //切片是引用类型数据 fmt.Println(a) } func main() { //test1() //var a int //test2(&a) //fmt.Println(a) //test3() //test4() //test5() test6() }
内置函数
1、close:主要 用来关闭channel
2、len: 用来求 长度, 比如string、array、slice、map、channel
3、new: 用来分配内存,主要用来分配值类型, 比如int、struct、string。返回的是指针
4、make: 用来分配内存,主要用来分配引 用类型, 比如chan、map、slice
5、append: 用来追加元素到数组、slice中
6、panic和recover: 用来做错误处理理
7、new和make的区别
函数
1、声明语法:func 函数名 (参数列列表) [(返回值列列表)] {}
func add() {
}
func add(a int, b int) {
}
func add(a int, b int) int {
}
func add(a int, b int) (int, int) {
}
func add(a, b int) (int, int) {
}
2、golang函数特点:
不支持重载, 一个包不能有两个名字一样的函数。
函数是一等公民,函数也是一种类型, 一个函数可以赋值给变量
匿名函数
多返回值
package main import "fmt" func add(a, b int) int { return a + b } func main() { //函数是一等公民,也可以和变量量一样进行行赋值 c := add fmt.Printf("%p %T %p %T ", c, add, c,add) sum := c(10, 20) fmt.Println(sum) sum = add(10, 20) fmt.Println(sum) }
package main import "fmt" type add_func func(int, int) int //自己定义数据类型
func add(a, b int) int { return a + b } func operator(op add_func, a int, b int) int { //使用传进来的函数,进行操作,op函数,类型为add_func
return op(a, b) } func main() { c := add fmt.Println(c) sum := operator(c, 100, 200) fmt.Println(sum) }
3、函数参数传递 方式:
1). 值传递
2). 引用传递
注意1: 无论是值传递,还是引用传递,传递给函数的都是变量量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝, 一般来说,地址拷贝更为高效。 而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。
3).函数参数传递方式:
注意2:map、slice、chan、指针、interface默认以引用的方式传递
4、命名返回值的名字:
func add(a, b int) (c int) { c = a + b return } func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a +b)/2 return }
5、_标识符, 用来忽略略返回值:
func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a +b)/2 return } func main() { sum, _ := calc(100, 200) }
6、可变参数:
func add(arg…int) int { //0或多个参数 } func add(a int, arg…int) int { //1个或多个参数 } func add(a int, b int, arg…int) int { //2个或多个参数 }
注意:其中arg是 一个slice,我们可以通过arg[index]依次访问所有参数通过len(arg)来判断传递参数的个数。
7、defer 用途:
1)当函数返回时,执行defer语句。因此,可以用来做资源清理
2)多个defer语句,按先进后出的方式执行
3) defer语句中的变量,在defer声明时就决定了。
defer 行为特征:
func a() { i := 0 defer fmt.Println(i) i++ return }
func f() {
for i := 0; i < 5; i++ {
defer fmt.Printf(“%d “, i)
}
}
defer 用途:
- 关闭文件句柄
func read() { file := open(filename) defer file.Close() // 文件操作 }
2.锁资源释放
func read() { mc.Lock() defer mc.Unlock() //其他操作 }
3.数据库连接释放
func read() { conn := openDatabase() defer conn.Close() //其他操作 }
递归函数
一个函数调用自己,就叫做递归。
package main import ( "fmt" ) func calc(n int) int { if n == 1 { return 1 } return calc(n-1) * n } func main() { n := calc(5) fmt.Println(n) }
递归的设计原则
1) 一个大的问题能够分解成相似的小问题
2)定义好出 口条件
闭包
- 闭包:一个函数和与其相关的引用环境组合而成的实体。
func Adder() func(int)int { var x int //在闭包中相当于全局变量
f := func(i int)int { x = x + i return x } return f } func testClosure() { f1 := Adder()//函数的调用,不是函数的赋值
fmt.Println(f1(10))//10
fmt.Println(f1(20))//30
fmt.Println(f1(30))//60 }
应用举例
package main import ( "fmt" "strings" ) func makeSuffixFunc(suffix string) func(string) string { return func(name string) string { if !strings.HasSuffix(name, suffix) { return name + suffix } return name } } func main() { func1 := makeSuffixFunc(".bmp") func2 := makeSuffixFunc(".jpg") fmt.Println(func1("test")) fmt.Println(func2("test")) }
包
1、golang中的包
a.golang 目前有150个标准的包,覆盖了几乎所有的基础库
b.golang.org有所有包的文档,没事都翻翻
线程同步 a.import(“sync”) b.互斥锁, var mu sync.Mutex c.读写锁, var mu sync.RWMutex
2、go get安装第三方包
go get github.com/gorilla/websocket,包会装在GOPATH路径下