a := 10// 推断为int b := "golang"// 推断为string c := 4.17// 推断为float64 d := true// 推断为bool e := "Hello"// 推断为string f := `Do you like my hat?`// 反引号作用与双引号一样 g := 'M'// 推断为int32 单引号表示为字符
第二种方式:var valueName valueType
1 2 3 4
var a int// 默认为0 var b string// 默认为空字符串"" var c float64// 默认为0 var d bool// 默认为false
第三种方式:
1 2
var message string message = "Hello World."
注意:
打印变量时:可以直接打印,或是使用替代符%v代表值,%T表示类型
变量如果不给值会有默认值
声明多种变量:
1 2
var a, b, c = 1, false, 3// 自动推断 var a, b, c int = 1, 2, 3// 这种情况必须全为int
作用域
声明在函数外,作用域属于包package scope;
声明函数内,作用域属于函数function scope
声明在代码块内,作用域就属于块block scope
1、包作用域:
1 2 3 4 5 6 7 8 9 10 11 12
package vis
import"fmt"
// 这两个变量都属于vis包内可见的,其他包想使用这两个变量必须导入vis包 var MyName = "Todd"// 开头大写,代表导出,其他包可以直接使用 var yourName = "Future Rock Star Programmer"// 小写表示私有
funcmain() { x := 0 increment := func()int { // increment是一个匿名函数 x++ // 函数使用了外部变量num,这是一个闭包 return x } fmt.Println(increment()) fmt.Println(increment()) }
关于什么是闭包?见下一节
3、块域:
1 2 3 4 5 6 7 8 9 10
funcmain() { x := 42 fmt.Println(x) { fmt.Println(x) y := "The credit belongs with the one who is in the ring." fmt.Println(y) } // fmt.Println(y) 块外部无法打印y }
关于域出现的特性的本质:
大括号定义了一个新的堆栈框架,因此定义了一个新的范围级别。
变量名称可以在新的大括号内重复使用。
当代码到达右大括号时,堆栈中的一小部分将被弹出
闭包
闭包是一个特殊的匿名函数, 它是匿名函数和相关引用环境组成的一个整体
闭包允许函数在其定义的作用域外部访问变量,即使在函数执行完毕后,这些变量仍然可以被引用和操作。
下面是一个go的demo:
1 2 3 4 5 6 7 8 9 10 11 12 13
func wrapper()func()int{ // 这里函数的返回值为func(),表示返回一个函数 x := 0 return func() int { x++ return x } }
funcmain() { a := "stored in a" b := "stored in b" fmt.Println("a - ", a) // b is not being used - invalid code // 如果一个变量没有使用到,编译器会报错:b declared but not used }
funcmain() { x := 5 zero(&x) fmt.Println(x) // x is 0 }
for循环
在go中,只有for循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// 方式一:使用分号隔开,同Java for i := 0; i <= 100; i++ { fmt.Println(i) } // 方式二:只有一个判断条件,这种很像while i := 0 for i < 10 { fmt.Println(i) i++ } // 死循环,直接for即可 i := 0 for { fmt.Println(i) i++ }
funcaverage(sf ...float64)float64 { fmt.Println(sf) fmt.Printf("%T \n", sf) var total float64 // 第一个参数是序号,第二个参数是值 for _, v := range sf { total += v } return total / float64(len(sf)) }
switch语句
switch语句和Java之类的语言的区别在于,case不会顺序执行,会自动break;
额外提供了fallthrough关键字来提供向下执行的功能。
demo1:
1 2 3 4 5 6 7 8 9 10 11
state := "Mhi" switch state { case"Daniel": fmt.Println("Wassup Daniel") case"Medhi": fmt.Println("Wassup Medhi") case"Jenny": fmt.Println("Wassup Jenny") default: fmt.Println("Have you no friends?") }
funcaverage(sf ...float64)float64 { fmt.Println(sf) fmt.Printf("%T \n", sf) var total float64 for _, v := range sf { total += v } return total / float64(len(sf)) }
...可以用来拆解数组
1 2 3 4 5 6 7 8 9 10 11 12 13
funcmain() { data := []float64{43, 56, 87, 12, 45, 57} n := average(data...) // 将数组拆散输入 fmt.Println(n) }
funcaverage(sf ...float64)float64 { total := 0.0 for _, v := range sf { total += v } return total / float64(len(sf)) }
fmt.Println(len(x)) fmt.Println(x[42]) // 普通方式 for i := 0; i < 256; i++ { x[i] = i } // foreach for i, v := range x { fmt.Printf("%v - %T - %b\n", v, v, v) if i > 50 { break } }
funcmain() { // 向上转型 var name interface{} = "Sydney" // 注意:只有空接口才有这个方法 // 两个返回值:值与是与不是 str, ok := name.(string) // name是不是string类型? if ok { fmt.Printf("%T\n", str) } else { fmt.Printf("value is not a string\n") } }
类型转换
空接口向下转型使用断言
1 2
var val interface{} = 7 fmt.Printf("%T\n", val.(int))
// w: pair<type: ,value: > var w io.Writer // w: pair<type: *os.File, value: "/dev/tty"的文件描述符> w = r.(io.Writer)// 这里的断言为什么能成功呢? w.Write([]byte("HELLO THIS IS A TEST!!!\n")) }
// 3、通过type获取字段 for i := 0; i < userType.NumField(); i++ { field := userType.Field(i) value := userValue.Field(i).Interface() fmt.Printf("%s: %v=%v\n", field.Name, field.Type, value) }
// 4、通过type获取方法 for i := 0; i < userType.NumMethod(); i++ { method := userType.Method(i) fmt.Printf("%s = %v", method.Name, method.Type) } // 5、获取标签的内容 for i := 0; i < userType.NumField(); i++ { tagInfo := userType.Field(i).Tag.Get("info") tagDoc := userType.Field(i).Tag.Get("doc") fmt.Println("info:", tagInfo, "doc", tagDoc) }