*本来这篇是想写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)
}
}