高级特性
1、闭包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package mainimport "fmt" func f1 (f func () ) { fmt.Println("this is f1" ) f() } func f2 (x, y int ) { fmt.Println("this is f2" ) fmt.Println(x + y) } func f3 (f func (int , int ) , x , y int ) func () { tmp := func () { f(x, y) } return tmp } func main () { ret := f3(f2, 100 , 200 ) fmt.Printf("%T\n" , ret) f1(ret) }
【使用1】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package mainimport "fmt" func adder1 () func (int ) int { var x int = 100 return func (y int ) int { x += y return x } } func adder2 (x int ) func (int ) int { return func (y int ) int { x += y return x } } func main () { ret := adder2(100 ) ret2 := ret(200 ) fmt.Println(ret2) }
【使用2】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport ( "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 () { jpgFunc := makeSuffixFunc(".jpg" ) txtFunc := makeSuffixFunc(".txt" ) fmt.Println(jpgFunc("test" )) fmt.Println(jpgFunc("呵呵.jpg" )) fmt.Println(txtFunc("test" )) fmt.Println(txtFunc("呵呵.txt" )) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package mainimport "fmt" func calc (base int ) (func (int ) int , func (int ) int ) { add := func (i int ) int { base += i return base } sub := func (i int ) int { base -= i return base } return add, sub } func main () { f1, f2 := calc(10 ) fmt.Println(f1(1 ), f2(2 )) fmt.Println(f1(3 ), f2(4 )) fmt.Println(f1(5 ), f2(6 )) }
2、递归
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package mainimport "fmt" func f (n uint64 ) uint64 { if n <= 1 { return 1 } return n * f(n-1 ) } func taijie (n uint64 ) uint64 { if n == 1 { return 1 } if n == 2 { return 2 } return taijie(n-1 ) + taijie(n-2 ) } func main () { ret := taijie(4 ) fmt.Println(ret) }
3、type 语句
自定义类型和类型别名
1 2 3 type myInt int type yourInt = int
4、地址与指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package mainimport "fmt" func main () { var a int a = 100 b := &a fmt.Printf("type a:%T type b:%T\n" , a, b) fmt.Printf("%p\n" , &a) fmt.Printf("%p\n" , b) fmt.Printf("%v\n" , b) fmt.Printf("%p\n" , &b) }
5、结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package mainimport "fmt" type person struct { name string age int gender string hobby []string } func main () { var p person p.name = "周林" p.age = 9000 p.gender = "男" p.hobby = []string {"篮球" , "足球" , "双色球" } fmt.Println(p) fmt.Printf("%T\n" , p) fmt.Println(p.name) var p2 person p2.name = "理想" p2.age = 18 fmt.Printf("type:%T value:%v\n" , p2, p2) var s struct { x string y int } s.x = "嘿嘿嘿" s.y = 100 fmt.Printf("type:%T value:%v\n" , s, s) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package mainimport "fmt" type person struct { name, gender string } func f (x person) { x.gender = "女" } func f2 (x *person) { x.gender = "女" } func main () { var p person p.name = "周林" p.gender = "男" f(p) fmt.Println(p.gender) f2(&p) fmt.Println(p.gender) var p2 = new (person) (*p2).name = "理想" p2.gender = "保密" fmt.Printf("%T\n" , p2) fmt.Printf("%p\n" , p2) fmt.Printf("%p\n" , &p2) var p3 = &person{ name: "元帅" , } fmt.Printf("%#v\n" , p3) p4 := &person{ "小王子" , "男" , } fmt.Printf("%#v\n" , p4) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package mainimport "fmt" type x struct { a int8 b int8 c int8 } func main () { m := x{ a: int8 (10 ), b: int8 (20 ), c: int8 (30 ), } fmt.Printf("%p\n" , &(m.a)) fmt.Printf("%p\n" , &(m.b)) fmt.Printf("%p\n" , &(m.c)) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package mainimport "fmt" type person struct { name string age int } type dog struct { name string } func newPerson (name string , age int ) *person { return &person{ name: name, age: age, } } func newDog (name string ) dog { return dog{ name: name, } } func main () { p1 := newPerson("元帅" , 18 ) p2 := newPerson("周林" , 9000 ) fmt.Println(p1, p2) d1 := newDog("周林" ) fmt.Println(d1) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package mainimport "fmt" type person struct { string int } func main () { p1 := person{ "周林" , 9000 , } fmt.Println(p1) fmt.Println(p1.string ) fmt.Println(p1.int ) }
其中反引号包裹的是对应在不同包中解析时准换的名称。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package mainimport ( "encoding/json" "fmt" ) type person struct { Name string `json:"name" db:"name" ini:"name"` Age int `json:"age"` } func main () { p1 := person{ Name: "周林" , Age: 9000 , } b, err := json.Marshal(p1) if err != nil { fmt.Printf("marshal failed, err:%v" , err) return } fmt.Printf("%v\n" , string (b)) str := `{"name":"理想","age":18}` var p2 person json.Unmarshal([]byte (str), &p2) fmt.Printf("%#v\n" , p2) }
6、方法和接收者
不同于函数,方法是作用于特定对象的。
Go语言中如果标识符首字母是大写的,就表示对外部包可见(暴露的,公有的)。
一般使用指针接收者
1 2 3 func (接收者变量 接收者类型) 方法名 (参数列表) (返回参数) { 函数体 }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 package mainimport "fmt" type dog struct { name string } type person struct { name string age int } func newPerson (name string , age int ) *person { return &person{ name: name, age: age, } } func newDog (name string ) dog { return dog{ name: name, } } func (d dog) wang () { fmt.Printf("%s:汪汪汪~" , d.name) } func (p *person) zhenguonian () { p.age++ } func (p *person) dream () { fmt.Println("不上班也能挣钱!" ) } func main () { p1 := newPerson("元帅" , 18 ) fmt.Println(p1.age) fmt.Println(p1.age) p1.zhenguonian() fmt.Println(p1.age) p1.dream() }
不能给别的包里面的类型添加方法,只能给自己包里的类型添加方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package mainimport "fmt" type myInt int func (m myInt) hello () { fmt.Println("我是一个int" ) } func main () { m := myInt(100 ) m.hello() }
7、接口 (interface)
接口是一种类型,是一种特殊的类型,它规定了变量有哪些方法。
基本使用,基本标准:是要实现了接口中的方法,就是该接口类型。
1 2 3 4 5 type 接口名 interface { 方法名1 (参数1 ,参数2. ..)(返回值1 ,返回值2. ..) 方法名2 (参数1 ,参数2. ..)(返回值1 ,返回值2. ..) ... }
一个变量如果实现了接口中规定的所有方法,那么这个变量就实现了这个接口,可以称为这个接口类型的变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package mainimport "fmt" type speaker interface { speak() } type cat struct {}type dog struct {}type person struct {}func (c cat) speak () { fmt.Println("喵喵喵~" ) } func (d dog) speak () { fmt.Println("旺旺旺~" ) } func (p person) speak () { fmt.Println("啊啊啊~" ) } func da (x speaker) { x.speak() } func main () { var c1 cat var d1 dog var p1 person da(c1) da(d1) da(p1) var ss speaker ss = c1 ss = d1 ss = p1 fmt.Println(ss) }
一般使用指针接收者,也就是对象的指针实现了接口。
使用值接收者实现接口,结构体类型和结构体指针类型的变量都能存;
指针接收者实现接口只能存结构体指针类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package mainimport "fmt" type animal interface { move() eat(string ) } type cat struct { name string feet int8 } func (c *cat) move () { fmt.Println("走猫步..." ) } func (c *cat) eat (food string ) { fmt.Printf("猫吃%s...\n" , food) } func main () { var a1 animal c1 := cat{"tom" , 4 } c2 := &cat{"假老练" , 4 } a1 = &c1 fmt.Println(a1) a1 = c2 fmt.Println(a1) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package mainimport "fmt" type animal interface { mover eater } type mover interface { move() } type eater interface { eat(string ) } type cat struct { name string feet int8 } func (c *cat) move () { fmt.Println("走猫步..." ) } func (c *cat) eat (food string ) { fmt.Printf("猫吃%s...\n" , food) }
相当于所有的类型都实现了空接口,也就是说所有值都能传进来。
空接口没有必要取名字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport "fmt" func show (a interface {}) { fmt.Printf("type:%T value:%v\n" , a, a) } func main () { var m1 map [string ]interface {} m1 = make (map [string ]interface {}, 16 ) m1["name" ] = "周林" m1["age" ] = 9000 m1["merried" ] = true m1["hobby" ] = [...]string {"唱" , "跳" , "rap" } fmt.Println(m1) show(false ) show(nil ) show(m1) }
8、类型断言
目的:想知道空接口接收的具体是什么?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package mainimport "fmt" type ff func () func assign (a interface {}) { fmt.Printf("%T\n" , a) str, ok := a.(string ) if !ok { fmt.Println("猜错了" ) } else { fmt.Println("传进来的是一个字符串:" , str) } } func assign2 (a interface {}) { fmt.Printf("%T\n" , a) switch t := a.(type ) { case string : fmt.Println("是一个字符串:" , t) case int : fmt.Println("是一个int:" , t) case int64 : fmt.Println("是一个int64:" , t) case bool : fmt.Println("是一个bool:" , t) case []int : fmt.Println("是一个slice:" , t) case map [string ]int : fmt.Println("是一个map[string]int:" , t) case func () : fmt.Println("是一个函数类型:" , t) } } func f () {} func main () { assign2(true ) assign2("哈哈哈" ) assign2(int64 (200 )) assign2([]int {1 , 2 , 3 }) assign2(map [string ]int {"a" : 1 }) assign2(f) }
9、包
【注意事项】
import 导入语句通常放在文件开头包声明语句下面;
导入的包名需要使用双引号包裹起来;
包名是从 $GOPATH/src/
后开始计算的,使用/
进行路径分隔;
Go语言中禁止循环导入包;
想被别的包调用的标识符都要首字母大写;
导入包的时候可以指定别名;
导入包不想使用包内部的标识符,需要使用匿名导入;
init方法的调用顺序:
【格式】
1 2 3 4 5 6 7 import 别名 "包的路径" import { 别名 "包的路径" } import _ "路径"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package calcimport "fmt" func init () { fmt.Println("import 我时自动执行..." ) } func Add (x, y int ) int { return x + y } --- package mainimport ( "fmt" mzyan "github.com/hustmzyan/day05/10calc" ) var x = 100 const pi = 3.14 func init () { fmt.Println("自动执行!" ) fmt.Println(x, pi) } func main () { ret := mzyan.Add(10 , 20 ) fmt.Println(ret) }
10、文件操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 package mainimport ( "bufio" "fmt" "io" "io/ioutil" "os" ) func readFromFile1 () { fileObj, err := os.Open("./main.go" ) if err != nil { fmt.Printf("open file failed, err:%v" , err) return } defer fileObj.Close() var tmp [128 ]byte for { n, err := fileObj.Read(tmp[:]) if err == io.EOF { fmt.Println("读完了" ) return } if err != nil { fmt.Printf("read from file failed, err:%v" , err) return } fmt.Printf("读了%d个字节\n" , n) fmt.Println(string (tmp[:n])) if n < 128 { return } } } func readFromFilebyBufio () { fileObj, err := os.Open("./main.go" ) if err != nil { fmt.Printf("open file failed, err:%v" , err) return } defer fileObj.Close() reader := bufio.NewReader(fileObj) for { line, err := reader.ReadString('\n' ) if err == io.EOF { return } if err != nil { fmt.Printf("read line failed, err:%v" , err) return } fmt.Print(line) } } func readFromFileByIoutil () { ret, err := ioutil.ReadFile("./main.go" ) if err != nil { fmt.Printf("read file failed, err:%v\n" , err) return } fmt.Println(string (ret)) } func main () { readFromFileByIoutil() }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 package mainimport ( "bufio" "fmt" "io/ioutil" "os" ) func writeDemo1 () { fileObj, err := os.OpenFile("./xx.txt" , os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644 ) if err != nil { fmt.Printf("open file failed, err:%v" , err) return } fileObj.Write([]byte ("zhoulin mengbi le!\n" )) fileObj.WriteString("周林解释不了!" ) fileObj.Close() } func writeDemo2 () { fileObj, err := os.OpenFile("./xx.txt" , os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644 ) if err != nil { fmt.Printf("open file failed, err:%v" , err) return } defer fileObj.Close() wr := bufio.NewWriter(fileObj) wr.WriteString("hello沙河\n" ) wr.Flush() } func writeDemo3 () { str := "hello 沙河" err := ioutil.WriteFile("./xx.txt" , []byte (str), 0666 ) if err != nil { fmt.Println("write file failed, err:" , err) return } } func main () { writeDemo3() }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 package mainimport ( "fmt" "io" "os" ) func f2 () { fileObj, err := os.OpenFile("./sb.txt" , os.O_RDWR, 0644 ) if err != nil { fmt.Printf("open file failed, err:%v\n" , err) return } tmpFile, err := os.OpenFile("./sb.tmp" , os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644 ) if err != nil { fmt.Printf("create tmp file failed, err:%v\n" , err) return } defer tmpFile.Close() var ret [1 ]byte n, err := fileObj.Read(ret[:]) if err != nil { fmt.Printf("read from file failed, err:%v" , err) return } tmpFile.Write(ret[:n]) var s []byte s = []byte {'c' } tmpFile.Write(s) var x [1024 ]byte for { n, err := fileObj.Read(x[:]) if err == io.EOF { tmpFile.Write(x[:n]) break } if err != nil { fmt.Printf("read from file failed, err:%v\n" , err) return } tmpFile.Write(x[:n]) } fileObj.Close() tmpFile.Close() os.Rename("./sb.tmp" , "./sb.txt" ) } func main () { f2() }