var x, y int//如果变量没有初始化,则默认为零值 var ( a int b bool ) var c, d int = 1, 2//可以并行赋值 var e, f ,_= 123, "hello", "discarded"//可以是不同类型,还可以用空白标识符_来抛弃值 funcmain(){ g, h := 123, "hello"//用:=初始化语句的用法只能在函数体中出现 } var binarynum int = 0b1100//二进制数字 var eightnum int = 0o14//八进制 var hexnum int = 0xc//十六进制
package main funcmain(){ //iota 只是在同一个 const 常量组内递增,每当有新的 const 关键字时,iota 计数会重新开始 const ( a = iota//0 b //1 c //2 d = "ha"//"ha" e //"ha" f = 100//100 g //100 h = iota//7 i //8 ) }
类型别名
使用type可以定义一个类型字面量
1
type arr3 [3]int
Chan类型
在go后加一个函数,就可以创建一个线程,函数可以为已定义的,也可以是匿名的
1 2 3 4 5 6 7 8 9 10 11 12 13
package main import"fmt" funcmain(){ fmt.Println("main start") gofunc(){ fmt.Println("goroutine")//由于Go语言的线程是并发机制,所以这行实际来不及执行 }() fmt.Println("main end") } /* main start main end */
让线程执行的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
package main import"fmt" import"time" funcmain(){ fmt.Println("main start") gofunc(){ fmt.Println("goroutine") }() time.Sleep(1*time.Second) fmt.Println("main end") } /* main start goroutine main end */
scores1 := map[string]int{"english": 80, "chinese": 85} for subject, score := range scores1 { ... } for subject := range scores1 { ... } for _, score := range scores1 { ... }
布尔类型
在Go语言中,不同类型间无法比较,因而以下表达式是错误的
1 2 3 4 5
//编译错误的表达式 var male bool = true if male == 1 {//不能将布尔类型与整数类型进行比较 ... }
控制流语句
if-else
Go要求else if 或else 两边的花括号必须在同一行,且要求条件表达式必须严格返回布尔类型的数据
在if 里可以允许先运行一个表达式,取得变量后,再对其进行判断
1 2 3
if age := 18; age >= 18 { fmt.Println("已经成年了") }
switch
switch从第一个判断表达式为true 的case开始执行,不需要break
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
package main import"fmt" funcmain(){ var x interface{} switch i := x.(type) { casenil: fmt.Printf("The type of x is %T",i) caseint: fmt.Printf("The type of x is int") casefunc(int)float64: fmt.Printf("The type of x is func(int)") casebool, string://多条件匹配 fmt.Printf("The type of x is bool or string") default: fmt.Printf("Unknown type") } } //The type of x is <nil>
funcmain() { name := "go" defer fmt.Println(name) name = "rust" defer fmt.Println(name) name = "c++" fmt.Println(name) } /* c++ rust go */
defer在return之后调用
1 2 3 4 5 6 7 8 9 10 11 12 13
var name string = "go" funcmyfunc()string{ deferfunc() { name = "python" }() fmt.Println("The name in myfunc is ", name) return name } funcmain(){ myname := myfunc() fmt.Println("The name in main is ", name) fmt.Println("The myname in main is ", myname) }
select
select 的用法类似于IO多路复用,可以同时监听的多个channel的消息状态
1 2 3 4 5 6 7 8 9 10
select { case <- ch1: ... case <- ch2: ... case ch3 <- 10: ... default: ... }
funcset_data(x int) { deferfunc(){ //recover()只能在defer域中才能生效 if err := recover(); err != nil { fmt.Println(err) } }() var arr [10]int arr[x] = 88//故意制造数组越界 } funcmain() { set_data(20) fmt.Println("everything is ok") } /*output runtime error: index out of range [20] with length 10 everything is ok */
面向对象
struct 结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
type Profile struct { name, gender string//相同类型的字段可以合并 age int mother, father *Profile } func(person Profile)FmtProfile(){ fmt.Println("name: ",person.name) fmt.Println("age: ",person.age) fmt.Println("gender: ",person.gender) } funcmain(){ xf := Profile{name: "熊昉"}//未被赋值的字段会自动赋为零值 xf.gender = "male" xf.age = 18 xf.FmtProfile() }
t := reflect.TypeOf(T{}) f1, _ := t.FieldByName("f1") fmt.Println(f1.Tag)//f one f4, _ := t.FieldByName("f4") fmt.Println(f4.Tag)//f four and five f5, _ := t.FieldByName("f5") fmt.Println(f5.Tag)//f four and five
使用Lookup方法
1 2 3 4 5
t := reflect.TypeOf(T2{}) f, _ := t.FieldByName("f") fmt.Println(f.Tag)//one:"1" two:"2" blank: "" v, ok := f.Tag.Lookup("one") fmt.Println("%s, %t", v, ok)
Get方法只是简单的包装了Lookup,但是丢弃了是否成功的结果
1 2 3 4
func(tag StructTag)Get(key string)string{ v, _ := tag.Lookup(key) return v }
进阶语法
反射
先看维基百科上的定义
在计算机科学中,反射是指计算机程序在运行时可以访问、检测和修改它本身状态或行为的一种能力。
Go语言圣经:
Go 语言提供了一种机制在运行时更新变量和检查它们的值、调用它们的方法,但是在编译时并不知道这些变量的具体类型,这称为反射机制
reflect.Value类型和reflect.Type类型
1 2 3 4
var x float64 = 3.4 fmt.Println("type:",reflect.TypeOf(x))//type: float64 //在reflect.TypeOf的函数签名里包含一个空接口 fmt.Println("value:",reflect.ValueOf(x))//value: 3.4
var x float64 = 3.4 v := reflect.ValueOf(x) fmt.Println("type:", v.Type()) fmt.Println("kind is float64:", v.Kind() == reflect.Float64) fmt.Println("value:", v.Float())
var x float64 = 34 v := reflect.ValueOf(x)//传递的是x的拷贝,而非x本身 fmt.Println("settability of v:", v.CanSet())//settability of v: false
传递指针则可写
1 2 3 4 5 6 7
var x float64 = 3.4 p := reflect.ValueOf(&x) v := p.Elem() fmt.Println("settability of v:", v.CanSet())//settability of v: true v.SetFloat(7.1) fmt.Println(v.Interface())//7.1 fmt.Println(x)//7.1