# 第一段go代码
1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 func add(a int, b int) int { 8 var sum int 9 sum = a + b 10 return sum 11 } 12 13 func main() { 14 var res int 15 res = add(100, 200) 16 fmt.Println("hello~Go!", "add(100,200)=", res), 17 18 }
输出结果:
golang语言特性
1. 垃圾回收
a. 内存自动回收,再也不需要开发人员管理内存
b. 开发人员专注业务实现,降低了心智负担
c. 只需要new分配内存,不需要释放
2. 天然并发
a. 从语言层面支持并发,非常简单
b. goroute,轻量级线程,创建成千上万个goroute成为可能
c. 基于CSP(Communicating Sequential Process)模型实现
# 一个简单的go并发展示(由2个文件hello.go和test.go组成)
1 //hello.go 主文件 2 package main 3 4 import ( 5 // 调用一个Sleep所需的时间模块 6 "time" 7 ) 8 9 func add(a int, b int) int { 10 var sum int 11 sum = a + b 12 return sum 13 } 14 15 //循环命令 16 func main() { 17 for i := 0; i < 100; i++ { 18 // 同包下面的函数可以直接使用"go"进行调用 19 go testPrint(i) 20 } 21 22 //一定要注意大小写字母 23 time.Sleep(time.Second) 24 } 25 26 27 //第二个文件test.go 同main()包下 28 package main 29 30 import ( 31 "fmt" 32 ) 33 34 func testGoroute(a int, b int) { 35 sum := a + b 36 fmt.Println(sum) 37 } 38 39 func testPrint(a int) { 40 fmt.Println(a) 41 }
输出结果部分截图:(从下面截图可以看出,这里在go下面实现一个并发是非常容易的)
# 死循环拷机代码改造
1 // hello.go 2 package main 3 4 import ( 5 "time" 6 ) 7 8 func add(a int, b int) int { 9 var sum int 10 sum = a + b 11 return sum 12 } 13 14 //循环命令 15 func main() { 16 for i := 0; i < 100; i++ { 17 // 同包下面的函数可以直接使用"go"进行调用 18 go testPrint(i) 19 } 20 //默认为1秒,下面为10秒(死循环时间) 21 time.Sleep(10 * time.Second) 22 } 23 24 25 // test.go 26 package main 27 28 import ( 29 "fmt" 30 ) 31 32 func testGoroute(a int, b int) { 33 sum := a + b 34 fmt.Println(sum) 35 } 36 37 func testPrint(a int) { 38 // 进行一个空循环(死循环) 39 40 for { 41 } 42 }
PS: 此代码会导致CPU占用达到100%,请勿在生产环境上执行。
3. channel
a. 管道,类似unix/linux中的pipe
b. 多个goroute之间通过channel进行通信
c. 支持任何类型
pipe: 变量名
make:
chan: 管道 ; (chan <数据类型>, <管道的容量>)
:= 赋值(Go的一种简化代码的方式)
e.g. 未简化版(需要两行) var loki int loki = 1 e.g. 简化版(仅需一行,自动匹配数据类型) loki := 1
<- 把右边的数据放到左边的变量
# 管道使用方法简单演示
1 //主函数调用的hello.go文件 2 3 package main 4 5 //主函数执行 6 func main() { 7 testPipe() 8 9 } 10 11 //pipe.go 管道代码的文件 12 package main 13 14 import ( 15 "fmt" 16 ) 17 18 func testPipe() { 19 //管道的设定格式 20 pipe := make(chan int, 3) 21 pipe <- 1 22 pipe <- 2 23 pipe <- 3 24 25 //定义取管道值的变量名 26 var t1 int 27 var t2 int 28 var t3 int 29 //变量取管道数据(遵从先进先出的原则) 30 t1 = <-pipe 31 t2 = <-pipe 32 t3 = <-pipe 33 // 取玩值后再给管道附一个值 34 pipe <- 4 35 fmt.Println("t1=", t1, "t2=", t2, "t3=", t3) 36 fmt.Println("channel length:", len(pipe)) 37 }
输出结果:
PS:超过管道设定的管道容量会产生死锁。
NOTE: 除了channel还可以通过"全局变量"来进行不同goroute数据交互,但是不推荐使用。
# Go 下面的格式化工具(帮你对齐代码)
gofmt
# goroute之间的交互代码演示(全局变量)
缺点: 数量多了,分不清楚
1 // hello.go 主main执行文件 2 package main 3 4 import ( 5 "fmt" 6 "time" 7 ) 8 9 // 定义全局变量 10 var pipe chan int 11 12 func add(a int, b int) { 13 sum := a + b 14 // 让程序模拟执行了3秒 15 time.Sleep(3 * time.Second) 16 pipe <- sum 17 18 } 19 func main() { 20 // 创建管道 21 pipe = make(chan int, 1) 22 // 创建goroute 23 go add(166, 500) 24 //创建变量,进行管道传值 25 sum := <-pipe 26 fmt.Println("res=", sum) 27 }
# goroute之间的交互代码演示(传参方式)
1 //hello.go 主main文件,传参方式交互 2 package main 3 4 import ( 5 "fmt" 6 "time" 7 ) 8 9 // 在这里进行形参定义,c属于形参 10 func add(a int, b int, c chan int) { 11 sum := a + b 12 // 让程序模拟执行了3秒 13 time.Sleep(3 * time.Second) 14 c <- sum 15 16 } 17 func main() { 18 // 定义非全局变量, 放在main函数下面 19 var pipe chan int 20 pipe = make(chan int, 1) 21 // 在这里进行实参传值 22 go add(166, 500, pipe) 23 sum := <-pipe 24 fmt.Println("res=", sum) 25 }
上面2个的执行结果一直,表示成功:
4. 多返回值
a. 一个函数返回多个值
# 多函数演示
1 // 主函数 hello.go 2 package main 3 4 import ( 5 "fmt" 6 ) 7 8 func main() { 9 res1, res2 := calc(100, 100) 10 fmt.Println("res1_SUM=", res1, "res2_AVERAGE=", res2) 11 } 12 13 // 多函数返回值 calc.go 14 package main 15 16 func calc(x int, y int) (int, int) { 17 sum := x + y 18 avg := (x + y) / 2 19 return sum, avg 20 }
PS: 多函数返回值类似Python,并且如果返回值有无用的值也类似Python可以使用“_”(但注意,这里的"-"是一种语法,仅能赋值不能引用)
5. 包的概念
a. 和Python一样,把相同功能的代码放到一个目录,称之为包
b. 包可以被其他包引用
c. main包是用来生成可执行文件, 每个程序只有一个main包
d. 包的主要用途是提高代码的可复用性
Go的编码只有UTF-8
Go项目目录路径规划
export GOPATH=X:/project/
%GOPATH%/src/go_dev/day1/example1/
%GOPATH%/vender/
%GOPATH%/pkg/
函数名想要被调用使用首字母“大写”函数名,不想被调用“小写”函数名
# 正确的使用方法
::calc 目录下面的文件
1 # addition.go 文件 2 package calc 3 4 // Add is just the sum of x and y 5 func Add(x int, y int) int { 6 res := x + y 7 return res 8 } 9 10 11 # subtraction.go 文件 12 package calc 13 14 // Sub is the value of x minus y 15 func Sub(x int, y int) int { 16 res := x - y 17 return res 18 }
::main 目录下面的文件
1 # start.go 文件 2 package main 3 4 import ( 5 "fmt" 6 "go_dev/day1/package_example/calc" 7 ) 8 9 func main() { 10 res := calc.Add(100, 200) 11 res2 := calc.Sub(100, 200) 12 fmt.Println("res-->", res, "res2-->", res2) 13 }
# 目录结构
# 生成.exe指定目录方式
go build -o <存放目录> <需要编译的go文件路径>
go build -o bin/calc go_dev/day1/package_example/main
# 通过参数的方式传入管道
# goroute_demo.go
1 package goroute 2 3 // Add is the sum of x and y to z(channl) 4 func Add(x int, y int, z chan int) { 5 // Pass the result of the sum of X and Y to Z 6 z <- (x + y) 7 }
# main.go
1 package main 2 3 import ( 4 "fmt" 5 "go_dev/day1/goroute_example/goroute" 6 ) 7 8 func main() { 9 pipe := make(chan int, 1) 10 // 打开额外的一个线程进行计算 11 go goroute.Add(111, 222, pipe) 12 res := <-pipe 13 fmt.Println("result-->: ", res) 14 }
作业:
HW--0. 去官网教程自学(不用深挖,但是需要全部过一遍)
发现官网教学有个离线版,顺便研究了下离线版的安装方法,简单说下:
a. 自己要有Go环境,并且清楚%GOPATH%路径在哪里,这个下面会有3个文件夹,分别是src,bin,pkg
b. 去github网站上download 离线版的tour的zip包
c. 放入%GOPATH% 下面 srcgithub.comGo-zh our(PS:这里还需要解决依赖问题,不过我是用梯子解决的https_proxy=socks5://127.0.0.1:10808)
d. 执行go install
e. 会在%GOPATH% 的bin目录中生产一个tour.exe
f. 执行即可
# 看教程领悟小技巧
1. 当连续两个或多个函数的已命名形参类型相同时,除最后一个类型以外,其它都可以省略。
1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 // func add(x int, y int) int { 这里原本写法,改用下面简写方式 8 func add(x, y int) int { 9 return x + y 10 } 11 12 func main() { 13 res := add(1, 2) 14 fmt.Println("Add result is : ", res) 15 }
2. 基本类型
bool 布尔型 string 字符串 int int8 int16 int32 int64 整形 uint uint8 uint16 uint32 uint64 uintptr 无符号整型 byte // uint8 的别名 rune // int32 的别名 // 表示一个 Unicode 码点 float32 float64 浮点型 complex64 complex128
3. 零值
没有明确初始值的变量声明会被赋予它们的 零值。 零值是: 数值类型为 0, 布尔类型为 false, 字符串为 ""(空字符串)。
4. 常量 const
常量的声明与变量类似,只不过是使用 const 关键字。
常量可以是字符、字符串、布尔值或数值。
常量不能用 := 语法声明。
# 写个例子呗
package main import ( "fmt" ) const Pi = 3.14 func main() { const Word = "世界" const Trush = true fmt.Println("Hello ", Word) fmt.Println("test once...", Trush) }
5. for
Go 只有一种循环结构:for 循环。 基本的 for 循环由三部分组成,它们用分号隔开: 初始化语句:在第一次迭代前执行 条件表达式:在每次迭代前求值 后置语句:在每次迭代的结尾执行 初始化语句通常为一句短变量声明,该变量声明仅在 for 语句的作用域中可见。 一旦条件表达式的布尔值为 false,循环迭代就会终止。 注意:和 C、Java、JavaScript 之类的语言不同,Go 的 for 语句后面的三个构成部分外没有小括号, 大括号 { } 则是必须的。
初始化语句和后置语句是可选的。
# 写个例子
1 # 常规fox 循环格式 2 package main 3 4 import ( 5 "fmt" 6 ) 7 8 func main() { 9 sum := 0 10 for item := 0; item < 10; item++ { 11 sum += item 12 } 13 fmt.Println(sum) 14 } 15 16 # 另外一种版本 17 package main 18 19 import ( 20 "fmt" 21 ) 22 23 func main() { 24 sum := 1 25 for ; sum < 1000; sum++ { 26 sum += sum 27 } 28 fmt.Println(sum) 29 }
# 把for 当“while”使用
1 # 此时你可以去掉分号,因为 C 的 while 在 Go 中叫做 for。 2 3 package main 4 5 import "fmt" 6 7 func main() { 8 sum := 1 9 for sum < 1000 { 10 sum += sum 11 } 12 fmt.Println(sum) 13 }
# 进行一次“死循环”
1 # 如果省略循环条件,该循环就不会结束,因此无限循环可以写得很紧凑。 2 package main 3 4 func main() { 5 for { 6 } 7 }
6. if
# e.g. Go 的 if
语句与 for
循环类似,表达式外无需小括号 ( )
,而大括号 { }
则是必须的。
1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 func testFunc(x int) string { 8 if x > 0 { 9 // 结果为True 执行这里 10 return "I'm nonZero" 11 } 12 // 结果为Flase执行这里,相当于else 13 return "I'm Zero" 14 } 15 16 func main() { 17 fmt.Println("result 1: ", testFunc(9), " ", "result 2: ", testFunc(0)) 18 19 }
# e.g. if 语句可以在条件表达式前执行一个简单的语句。该语句声明的变量作用域仅在 if 之内。
1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 func testFunc(x int) string { 8 // 这里变量v的作用域仅在if里面 9 if v := 15; x < v { 10 return "Your number is smaller than mine" 11 } 12 if v := 15; x > v { 13 return "your number is bigger than mine" 14 } 15 return "You guessed it" 16 } 17 18 func main() { 19 fmt.Println(testFunc(15)) 20 fmt.Println(testFunc(1)) 21 fmt.Println(testFunc(20)) 22 23 }
7. if 和 else
# e.g. 在 if
的简短语句中声明的变量同样可以在任何对应的 else
块中使用。
1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 func testFunc(x int) (int, string) { 8 // 这里变量v的作用域在if和else里面 9 if v := 99; x == v { 10 return v, "is Right!" 11 } else { 12 return v, "than Bigger OR Smaller mine!" 13 } 14 // 这里开始就不能在调用变量v 15 return 0, "Over" 16 } 17 18 func main() { 19 fmt.Println(testFunc(99)) 20 fmt.Println(testFunc(1)) 21 22 }
练习:循环与函数 http://192.168.24.175:3999/flowcontrol/8 部分(8/14) 暂停 (2020.11.27)
HW--1. 使用fmt 分别打印字符串、二进制、十进制、十六进制、浮点数
思路:
官方文档去寻找答案
https://golang.org/pkg/fmt/
# 整形的一些格式介绍
# 浮点数相关介绍
# 最终作业
1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 func main() { 8 str, bin, dec, hex, flo := "Loki", 10, 10, 10, 10.00 9 fmt.Printf("string-->: %v ", str) 10 fmt.Printf("binary-->: %b ", bin) 11 fmt.Printf("decimal-->: %d ", dec) 12 fmt.Printf("hexadecimal-->: %x ", hex) 13 fmt.Printf("float-->: %.2f ", flo) 14 15 }
# 输出结果,如下