本文最后更新于:2020年7月2日 晚上
* 本来这篇是想写docker的基本操作总结的。。。想想还是写这个吧。。。→_→ *
变量声明使用 := 方式时,左值必须是未声明的,否则会出现编译错误
//.\main.go:8:4: no new variables on left side of := package main import "fmt" func main() { var a int = 10 var b int = 20 b := 30 fmt.Print(a, b) }
变量声明了,就必须要使用,否则会出现编译错误
//.\main.go:7:6: b declared and not used package main import "fmt" func main() { var a int = 10 var b int = 20 fmt.Print(a) }
const修饰符的作用范围为同时修饰的所有常量
//.\main.go:7:4: cannot assign to a //.\main.go:8:4: cannot assign to b package main import "fmt" func main() { const a, b int = 10, 20 a = 10 b = 20 fmt.Print(a, b) }
++自增和- -自减运算符类比C语言,相当于前置的自增和自减,而且go语言中不区分前置或后置
//.\main.go:9:2: syntax error: unexpected ++, expecting } package main import "fmt" func main(){ var a int = 10 var b int = 20 ++a b++ fmt.Print(a, b) }
不能使用++自增或- -自减运算符初始化变量和对变量赋值
//.\main.go:7:15: syntax error: unexpected ++ at end of statement //.\main.go:10:7: syntax error: unexpected ++ at end of statement package main import "fmt" func main(){ var a int = 10 var b int = a++ var c int = 20 c = a++ fmt.Print(a, b, c) }
if…else 语句中的 else 必须和 if 的 ‘ } ‘ 在同一行,否则编译错误
//.\main.go:11:2: syntax error: unexpected else, expecting } package main import "fmt" func main() { var a int = 30 if a < 20 { fmt.Print("a<20") } else { fmt.Print("a>=20") } }
switch 中的 case和default分支不用添加break
//代码运行成功 package main import "fmt" func main() { var a int = 10 switch a { case 1: fmt.Println("1") case 2: fmt.Println("2") case 10: fmt.Println("10") default: fmt.Println("unknow") } }
switch 中 也可以不用添加表达式
//代码运行成功 package main import "fmt" func main() { var a int = 10 switch { case a == 1: fmt.Println("1") case a == 2: fmt.Println("2") case a == 10: fmt.Println("10") default: fmt.Println("unknow") } }
switch的case分支的常量表达式可以同时测试多个值
//代码运行成功 package main import "fmt" func main() { var a int = 10 switch { case a == 1, a == 2: fmt.Println("1 or 2") case a == 10, a == 20: fmt.Println("10 or 20") case a == 100, a == 200: fmt.Println("100 or 200") default: fmt.Println("unknow") } }
switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型
package main import "fmt" func main() { var x interface{} switch i := x.(type) { case nil: fmt.Printf("%T", i) case int: fmt.Printf("int") case float64: fmt.Printf("float64") case func(int) float64: fmt.Printf("func(int)") case bool, string: fmt.Printf("bool or string") default: fmt.Printf("unknow") } }
select 语句。。这个现在还没看懂。。先MARK
Learning...
for循环语句range格式,遍历数组
//i为下标 //x为元素的值 //0 1 //1 2 //2 3 //3 4 //4 5 package main import "fmt" func main() { var number = [5]int{1, 2, 3, 4, 5} for i, x := range number { fmt.Println(i, x) } }
for循环语句和C语言中的while循环语句比较
//0 1 2 3 4 5 6 7 8 9 package main import "fmt" func main() { var a int = 0 for a < 10 { fmt.Printf("%d ", a) a++ } }
for循环语句和C语言中的for循环语句比较
//0 1 2 3 4 5 6 7 8 9 package main import "fmt" func main() { var a int = 0 for a = 0; a < 10; a++ { fmt.Printf("%d ", a) } }
函数的结构与C语言中的函数结构有很大不同,函数调用相似
//10 10 //true package main import "fmt" func fun(num1 *int, num2 *int) bool { fmt.Println(*num1, *num2) if *num1 == *num2 { return true } else { return false } } func main() { var a int = 10 var b int = 10 var flag bool = fun(&a, &b) fmt.Print(flag) }
函数可以同时返回多个值
//hello world package main import "fmt" func fun(str1 string, str2 string) (string, string) { return str2, str1 } func main() { str1, str2 := fun("world", "hello") fmt.Println(str1, str2) }
函数可以作为值使用,神奇~
//-1 package main import "fmt" func main() { tmp := func(x int) int { return -x } fmt.Print(tmp(1)) }
函数支持匿名函数,可作为闭包。匿名函数是一个”内联”语句或表达式。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
//1 2 3 package main import "fmt" func first() func() int { i := 0 return func() int { i++ return i } } func main() { tmp := first() fmt.Println(tmp(), tmp(), tmp()) }
函数也可以成为自定义类型的一个方法
//10 abc package main import "fmt" //自定义类型 type student struct { num int name string } //方法getNum func (stu student) getNum() int { return stu.num } //方法getName func (stu student) getName() string { return stu.name } func main() { var st student st.num = 10 st.name = "abc" //对象调用其方法 fmt.Println(st.getNum(), st.getName()) }
数组的声明、初始化、赋值、访问
//[0 0 0 0 0 0 0 0 0 0] //100 1 2 3 4 5 6 7 8 9 [100 1 2 3 4 5 6 7 8 9] package main import "fmt" func main() { var arr [10]int var number = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} number[0] = 100 fmt.Println(arr) var i int = 0 for i = 0; i < 10; i++ { fmt.Printf("%d ", number[i]) } fmt.Println(number) }
二维数组的初始化
//[[1 2 3] [4 5 6] [7 8 9]] package main import "fmt" func main() { var number = [3][3]int{ {1, 2, 3}, {4, 5, 6}, {7, 8, 9}} fmt.Println(number) }
函数参数为数组,必须同时显示的写出数组元素个数或同时隐藏数组的元素个数
//0 1 2 3 4 5 6 7 8 9 10 package main import "fmt" func getNum(number []int) int { var i int = 0 for i = 0; i < 10; i++ { fmt.Printf("%d ", number[i]) } return len(number) } func main() { var number = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} num := getNum(number) fmt.Println(num) }
//0 1 2 3 4 5 6 7 8 9 10 package main import "fmt" func getNum(number [10]int) int { var i int = 0 for i = 0; i < 10; i++ { fmt.Printf("%d ", number[i]) } return len(number) } func main() { var number = [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} num := getNum(number) fmt.Println(num) }
指针数组的初始化和使用
//0 1 2 3 4 5 6 7 8 9 package main import "fmt" func main() { var number = [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} var num [10]*int for i := 0; i < 10; i++ { num[i] = &number[i] } for i := 0; i < 10; i++ { fmt.Printf("%d ", *num[i]) } }
二级指针的初始化和使用
//10 10 10 package main import "fmt" func main() { var i int = 10 var ptr1 *int = &i var ptr2 **int = &ptr1 fmt.Printf("%d %d %d", i, *ptr1, **ptr2) }
结构体的定义和初始化方式,注意结构体变量和结构体指针变量访问结构体成员时只有 . 一种方式,此处和C语言的结构体语法不同
//111 //zhangsan //man //20 //111 //zhangsan //man //20 package main import "fmt" type studentInfo struct { id int name string sex string age int } func getInfo(stu studentInfo) { fmt.Println(stu.id) fmt.Println(stu.name) fmt.Println(stu.sex) fmt.Println(stu.age) } func getInfoByPtr(stuPtr *studentInfo) { fmt.Println(stuPtr.id) fmt.Println(stuPtr.name) fmt.Println(stuPtr.sex) fmt.Println(stuPtr.age) } func main() { var stu studentInfo stu.id = 111 stu.name = "zhangsan" stu.sex = "man" stu.age = 20 getInfo(stu) var stuPtr *studentInfo = &stu getInfoByPtr(stuPtr) }
切片(Slice),长度不固定,可以理解为动态数组。Slice有两个属性:length即当前元素的容量大小,capacity即可以最大容纳元素的容量大小。Slice的定义如下
//make([]T, length, capacity) //len = 0 cap = 0, slice = [] //len = 10 cap = 10, slice = [0 0 0 0 0 0 0 0 0 0] //len = 10 cap = 10, slice = [0 0 0 0 0 0 0 0 0 0] //len = 5 cap = 10, slice = [0 0 0 0 0] package main import "fmt" func printSlice(slice []int) { fmt.Printf("len = %d cap = %d, slice = %v\n", len(slice), cap(slice), slice) } func main() { var slice1 []int printSlice(slice1) var slice2 = make([]int, 10) printSlice(slice2) var slice3 = make([]int, 10, 10) printSlice(slice3) slice4 := make([]int, 5, 10) printSlice(slice4) }
Slice的初始化如下:startIndex代表起始下标,endIndex代表终止下标,但在初始化时的实际范围是startIndex~endIndex-1。
缺省endIndex表示一直到最后一个元素,缺省startIndex表示从第一个元素开始。
当startIndex不是从arr[0]开始时,会将新切片的cap值改变为:原cap的值减startIndex。//s := arr[startIndex:endIndex] //len = 10 cap = 10, slice = [0 1 2 3 4 5 6 7 8 9] //len = 10 cap = 10, slice = [0 1 2 3 4 5 6 7 8 9] //len = 10 cap = 10, slice = [0 1 2 3 4 5 6 7 8 9] //len = 2 cap = 9, slice = [1 2] //len = 9 cap = 9, slice = [1 2 3 4 5 6 7 8 9] //len = 3 cap = 10, slice = [0 1 2] //len = 2 cap = 8, slice = [2 3] package main import "fmt" func printSlice(slice []int) { fmt.Printf("len = %d cap = %d, slice = %v\n", len(slice), cap(slice), slice) } func main() { var slice1 = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} printSlice(slice1) slice2 := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} printSlice(slice2) //数组arr var arr = [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} slice3 := arr[:] printSlice(slice3) slice4 := arr[1:3] printSlice(slice4) slice5 := arr[1:] printSlice(slice5) slice6 := arr[:3] printSlice(slice6) slice7 := slice5[1:3] printSlice(slice7) }
未初始化的切片Slice默认为nil,len为0,cap为0
//len = 0, cap = 0, slice = [] //slice is nil package main import "fmt" func printSlice(slice []int) { fmt.Printf("len = %d, cap = %d, slice = %v\n", len(slice), cap(slice), slice) } func main() { var slice []int printSlice(slice) if slice == nil { fmt.Printf("slice is nil\n") } }
Slice切片的append()追加和copy()拷贝。
当切片长度len等于切片容量cap时,再append()追加数据,此时切片cap容量增长,且默认扩容2倍。//len = 0, cap = 0, slice = [] //len = 1, cap = 1, slice = [0] //len = 2, cap = 2, slice = [0 1] //len = 5, cap = 6, slice = [0 1 2 3 4] //len = 5, cap = 12, slice = [0 1 2 3 4] package main import "fmt" func printSlice(slice []int) { fmt.Printf("len = %d, cap = %d, slice = %v\n", len(slice), cap(slice), slice) } func main() { var slice []int printSlice(slice) //此时cap默认扩容2倍 slice = append(slice, 0) printSlice(slice) //此时cap默认扩容2倍 slice = append(slice, 1) printSlice(slice) //此时cap扩容规则出现变化,同时append追加多个数据时,cap会扩容到向上最近的偶数数值,以减少cap容量的浪费 slice = append(slice, 2, 3, 4) printSlice(slice) slice2 := make([]int, len(slice), cap(slice)*2) copy(slice2, slice) printSlice(slice2) }
Slice切片的append()并没有改变参数中的原切片,而是改变了接受返回值的切片
//[1 2 8 4] //[1 2 8 4] //[1 2 8 4] //[1 2 9 4 5] package main import "fmt" func main() { original := []int{1, 2, 3, 4} //a slice with a len and cap of 4 other := original other[2] = 8 fmt.Println(original) fmt.Println(other) other = append(original, 5) other[2] = 9 fmt.Println(original) fmt.Println(other) }
range(范围)用来循环迭代array(数组)、slice(切片)、channel(通道)、map(集合)
//slice package main import "fmt" func main(){ nums := []int{1, 2, 3} sum := 0 for _, num := range nums{ sum += num } fmt.Print(sum) }
//slice package main import "fmt" func main(){ kvs := map[string]string{"1": "one", "2": "two"} for k, v := range kvs{ fmt.Printf("%s -> %s\n", k, v) } }
map是无序的键值对集合,delete函数删除map中的元素
package main import "fmt" func main(){ //定义map集合 var studentName map[int]string //初始化创建集合 studentName = make(map[int]string) studentName[0] = "zhangsan" studentName[1] = "lisi" studentName[2] = "wangwu" //由于map是hash表实现的,所以每次的迭代结果不确定 for ID := range studentName{ fmt.Printf("%d -> %s\n", ID, studentName[ID]) } //删除key为0的元素 delete(studentName, 0) fmt.Println("delete", 0) for ID := range studentName{ fmt.Printf("%d -> %s\n", ID, studentName[ID]) } }
interface接口,和JAVA中的接口相似
package main import ( "fmt" ) type Action interface{ sleep() eat() } type Human struct{ } func(hum Human) sleep(){ fmt.Println("human sleeping") } func(hum Human) eat(){ fmt.Println("human eating") } type Dog struct{ } func(dog Dog) sleep(){ fmt.Println("dog sleeping") } func(dog Dog) eat(){ fmt.Println("dog eating") } func main(){ var action Action action = new(Human) action.sleep() action = new(Dog) action.eat() }
错误处理
package main import ( "fmt" ) // 定义一个 DivideError 结构 type DivideError struct { dividee int divider int } // 实现 `error` 接口 func (de *DivideError) Error() string { strFormat := ` Cannot proceed, the divider is zero. dividee: %d divider: 0 ` return fmt.Sprintf(strFormat, de.dividee) } // 定义 `int` 类型除法运算的函数 func Divide(varDividee int, varDivider int) (result int, errorMsg string) { if varDivider == 0 { dData := DivideError{ dividee: varDividee, divider: varDivider, } errorMsg = dData.Error() return } else { return varDividee / varDivider, "no error" } } func main() { // 正常情况 result, errorMsg := Divide(100, 10) if errorMsg == "no error" { fmt.Println("100/10 = ", result, errorMsg) } // 当被除数为零的时候会返回错误信息 result, errorMsg = Divide(100, 0) if errorMsg != "no error" { fmt.Println("errorMsg is: ", result, errorMsg) } }
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!