一、基础
1.1 条件判断
package main
import "fmt"
func main() {
var a int = 10
if a < 20 {
fmt.Printf("a less 20\n" )
}
fmt.Printf("The value of a is %d\n", a)
a = 100
if a < 20 {
fmt.Printf("a less 20\n" )
}else{
fmt.Printf("a not less 20\n" )
}
fmt.Printf("The value of a is %d\n", a)
a = 20
if a < 20 {
fmt.Printf("a less 20\n" )
}else if a == 20 {
fmt.Printf("a == 20\n" )
}else {
fmt.Printf("a more 20\n" )
}
fmt.Printf("The value of a is %d\n", a)
}
执行结果
(base) desktop-6rkqqec:study songbw$ go run conditional.go
a less 20
The value of a is 10
a not less 20
The value of a is 100
a == 20
The value of a is 20
1.2 循环
package main
import "fmt"
//Print multiplication table
func gotoTag() {
for m := 1; m < 10; m++ {
n := 1
LOOP:
if n <= m {
fmt.Printf("%dx%d=%d ", n, m, m*n)
n++
goto LOOP
} else {
fmt.Println("")
}
}
}
func main() {
//Similar to the for loop of C
sum := 0
for i := 0; i <= 10; i++ {
sum += i
}
fmt.Println(sum)
//Similar to the while loop of C
sum = 1
for sum <= 10 {
sum += sum
}
fmt.Println(sum)
sum = 1
for sum <= 10 {
sum += sum
}
fmt.Println(sum)
//For-each range
numbers := [6]int{1, 2, 3, 5}
for i, x := range numbers {
fmt.Printf("第 %d 位 x 的值 = %d\n", i, x)
}
//break without tags
//This Use of break is similar to C + + or C
fmt.Println("---- break ----")
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
break
}
}
//use tags for break
fmt.Println("---- break label ----")
reBreak:
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
break reBreak
}
}
//continue without tags
//This Use of continue is similar to C + + or C
fmt.Println("---- continue ---- ")
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
continue
fmt.Printf("after continue, i2:%d\n", i2)
}
}
//use tags for continue
fmt.Println("---- continue label ----")
reContinue:
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
continue reContinue
fmt.Printf("after continue, i2:%d\n", i2)
}
}
fmt.Println("Print multiplication table")
gotoTag()
}
执行结果
(base) localhost:study songbw$ go run csdnLoop.go
55
16
16
第 0 位 x 的值 = 1
第 1 位 x 的值 = 2
第 2 位 x 的值 = 3
第 3 位 x 的值 = 5
第 4 位 x 的值 = 0
第 5 位 x 的值 = 0
---- break ----
i: 1
i2: 11
i: 2
i2: 11
i: 3
i2: 11
---- break label ----
i: 1
i2: 11
---- continue ----
i: 1
i2: 11
i2: 12
i2: 13
i: 2
i2: 11
i2: 12
i2: 13
i: 3
i2: 11
i2: 12
i2: 13
---- continue label ----
i: 1
i2: 11
i: 2
i2: 11
i: 3
i2: 11
Print multiplication table
1x1=1
1x2=2 2x2=4
1x3=3 2x3=6 3x3=9
1x4=4 2x4=8 3x4=12 4x4=16
1x5=5 2x5=10 3x5=15 4x5=20 5x5=25
1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36
1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49
1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64
1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81
解释:
从代码中可以看出,golang中的contine和break 比c或者c++ 中的功能强大了一丢丢,就是可以加标记,来标识退出或者继续哪一层级的循环,当然或许c或者c++ 中也有这样的功能,可能我不知道,我所接触到的实际工作中不加标记的break和continue已经可以满足需求了
1.3 switch
package main
import "fmt"
func main(){
var grade string = "B"
var marks int = 90
switch marks{
case 90: grade = "A"
case 80: grade = "B"
case 50,60,70 : grade = "C"
default: grade = "D"
}
switch{
case grade == "A" :
fmt.Printf("excellent!\n" )
case grade == "B", grade == "C" :
fmt.Printf("good\n" )
case grade == "D" :
fmt.Printf("pass\n" )
case grade == "F":
fmt.Printf("not pass\n" )
default:
fmt.Printf("bad\n" );
}
fmt.Printf("your level is %s\n", grade );
}
执行结果
(base) desktop-6rkqqec:study songbw$ go run switch_stat.go
excellent!
your level is A
switch比较简单,如果switch 后面有类型按类型判断,如果没类型,就按照 bool 值判断,如果一个case满足了,就不会走下一个 case
1.4 map 数据结构
1.4.1 map中用list
package main
import "fmt"
func main() {
//Initialization
//var userInfoMap = map[string]string{"name": "songbw", "age": "25"}
var userInfoMap = map[string]string{}
userInfoMap["sex"] = "male"
fmt.Printf("userInfoMap=%v\n", userInfoMap)
/*var userInfoMap1 map[string]string
//Not initialized, is an empty map, nil map cannot be used to store key value pairs
userInfoMap1["name"] = "lucy"
fmt.Printf("userInfoMap1=%v\n", userInfoMap1)*/
var userInfoMap1 map[string]string
//Need to create a map
userInfoMap1 = make(map[string]string)
userInfoMap1["name"] = "lucy"
fmt.Printf("userInfoMap1=%v\n", userInfoMap1)
//test list
var userInfoMap2 map[string][]uint
userInfoMap2 = make(map[string][]uint)
var score2 []uint
score2 = append(score2, 98)
userInfoMap2["songbw"] = score2
fmt.Printf("userInfoMap2=%v\n", userInfoMap2)
testListMem := userInfoMap2["songbw"]
testListMem[0] = 100
fmt.Printf("after update 98 to 100=%v\n", userInfoMap2)
testListMem = append(testListMem, 1)
fmt.Printf("after add data 1,userInfoMap2, wrong=%v\n", userInfoMap2)
userInfoMap2["songbw"] = testListMem
fmt.Printf("after add data 1,userInfoMap2, right=%v\n", userInfoMap2)
}
执行结果
userInfoMap=map[sex:male]
userInfoMap1=map[name:lucy]
userInfoMap2=map[songbw:[98]]
after update 98 to 100=map[songbw:[100]]
after add data 1,userInfoMap2, wrong=map[songbw:[100]]
after add data 1,userInfoMap2, right=map[songbw:[100 1]]
说明:
对于 map userInfoMap2
a、
修改 map userInfoMap2 中的数据是没问题的,显然将98修改成了100,那是因为,我们拿到的 list 可能是引用
b、
拿出 songbw 对应的 list 并添加数据,发现map中,songbw 对应的list 的数据,并没有增加,正确的做法,是把 list 重新赋值给 map ,如下
userInfoMap2["songbw"] = testListMem
我是这么理解这个问题的:
songbw 这个 key ,实际可能存的是 list 的地址,如果改动地址里面对应的元素,那没问题,songbw 对应的 list中的数据,会发生相应的改变,但是如果添加数据的话, list 的空间可能会不够用,所以可能重新申请内存,会产生新的 list 地址,那么显然,map中的 list 地址还是以前的啊,要想变成新的 list 地址,需要重新赋值啊
1.4.2 map中用过指针
package main
import "fmt"
type PoolConfig struct {
EnableOverflow bool
GroupID []int
}
func main() {
var tmpPPoolConfig = make(map[int]*PoolConfig)
tmpPPoolConfig[10] = &PoolConfig{
EnableOverflow: false,
GroupID: []int{100},
}
pGroupConfig := tmpPPoolConfig[10]
pGroupConfig.GroupID = append(pGroupConfig.GroupID, 22)
fmt.Printf("pGroupConfig=%v\n", pGroupConfig)
fmt.Printf("tmpPPoolConfig=%v\n", tmpPPoolConfig[10].GroupID)
var tmpPoolConfig = make(map[int]PoolConfig)
tmpPoolConfig[20] = PoolConfig{
EnableOverflow: false,
GroupID: []int{200},
}
groupConfig := tmpPoolConfig[20]
groupConfig.GroupID = append(groupConfig.GroupID, 32)
fmt.Printf("groupConfig=%v\n", groupConfig)
fmt.Printf("wrong tmpPoolConfig=%v\n", tmpPoolConfig[20].GroupID)
tmpPoolConfig[20] = groupConfig
fmt.Printf("right tmpPoolConfig=%v\n", tmpPoolConfig[20].GroupID)
}
执行结果:
pGroupConfig=&{false [100 22]}
tmpPPoolConfig=[100 22]
groupConfig={false [200 32]}
wrong tmpPoolConfig=[200]
right tmpPoolConfig=[200 32]
说明:
这个例子说明了,golang 的指针和c++ 的指针,本质上是一样,显然,对于 map tmpPPoolConfig ,value值存的是指针,数据就可以加进去,因为访问的是内存,而对于 map tmpPoolConfig,数据就要通过重新赋值的方式,才能够加进去
二 编译
2.1 go build
golang 代码写完后,如何生成可执行程序呢?
1、要把你写的golang代码放到 src 目录下,包括第三方源代码
2、设置环境变量 GOPATH是src的上一级目录
3、保证自己代码中import 过来的包是可以找到的,那么怎么算是可以找到的呢?
执行
ll $GOPATH/src/import下的目录
是可以找到相应的包的,这里要注意,import 后面的仅仅是包所在的目录而已,具体的包是在这个目录下面的,因为包所在的目录可以和包不是一个名字的,具体例子吧:
GOPATH设置如下
(base) localhost:bin songbw$ echo $GOPATH
/Users/songbw/OwnProject/go/smallCCNP
import 语句如下:
import (
"pkg/api"
)
如下
(base) localhost:smallCCNP songbw$ ll $GOPATH/src/pkg/api
total 8
-rw-r--r-- 1 songbw staff 303 3 29 10:15 zapis.go
是存在的,并且虽然引入的是api目录,但文件 zapis.go中标识的包是 package zapis ,所以import 的是 pkg/api ,而不是 pkg/zapis
4、使用 go build 生成可执行程序
go build -o smallCCNP pkg
-o 不解释了,和c/c++ 中的一样,pkg就是golang代码所在的目录,这条命令可以在终端的任何一个位置执行,因为,pkg会拼上 $GOPATH/src,而我的源代码就是放在 $GOPATH/src/pkg下面的