4.控制语句
4.1条件控制语句
4.1.1if-elseif-else
-
与clang不同,if不需要加()
if <condition1> {<block1> } else if <condition2> {<block2> } else {<block0> }
-
示例
a := 10 if a > 5 {fmt.Println("a > 5") } else if a == 5 {fmt.Println("a == 5") } else {fmt.Println("a < 5") }
4.1.2switch-case语句
-
switch-case
switch <variable> { case <value1>:<block1> case <value2>:<block2> ... default:<block0> }switch { case <condition1>:<block1> case <condition2>:<block2> ... default:<block0> }
-
示例
package mainfunc main() {a := 5switch a { // value值去判断case 1:println("a = 1")case 2:println("a = 2")case 3: println("a = 3")case 4:println("a = 4")case 5:println("a = 5")}score := 90switch { // 表达式case score > 90:println("A")case score > 80:println("B")case score > 70:println("C")case score > 60:println("D")default:println("E")} }
4.1.3select-case
-
格式
select { case <expression1>:<block1> case <expression2>:<block2> default:<block0> }
- expression必须是通信操作
- select讲随机抽取一个case,如果通信成功则运行
block
;如果失败才执行default
-
示例
package mainimport ("fmt""time" )var c1 = make(chan string) var c2 = make(chan string)func Thread1() {time.Sleep(time.Millisecond * 2100)c1 <- "Thread1 is ready." }func Thread2() {time.Sleep(time.Millisecond * 2100)c1 <- "Thread2 is ready." }func main() {go Thread1() // 加go,开辟线程,去接受datago Thread2()// time.Sleep(10 * time.Millisecond)for i := 0; i < 10; i++ {select {case msg1 := <-c1:fmt.Println(msg1)case msg2 := <-c2:fmt.Println(msg2)default:fmt.Println("default")time.Sleep(time.Millisecond * 500)}} }
default default default default default Thread2 is ready. Thread1 is ready. default default defaultdefault default default default default Thread1 is ready. Thread2 is ready. default default default
- 这两种都有可能,因为case是随机的
4.2循环控制语句
4.2.1for语句
Golang | Clang |
---|---|
for ; ; { } | for (; ; ) { ; } |
for { } | while () { ; } |
for { } | while (true) { ; } |
- Golang 中的 for 语句 ; 间的语句也可以是空语句
-
continue:跳转到下一个循环
for i := 0; i < 5; i++ {if i == 3 {continue}fmt.Println(i) }// 0 // 1 // 2 // 4
-
break:跳出循环
for i := 0; i < 5; i++ {if i == 3 {break}fmt.Println(i) }// 0 // 1 // 2
-
goto:跳转到指定标签
for i := 0; i < 5; i++ {if i == 3 {goto tag}fmt.Println(i) } tag:// 0 // 1 // 2
-
for-range
slice := []int{1, 2, 3, 4, 5} for key, value := range slice {fmt.Println(key, value) }channel := make(chan int, 10) for value := range channel {fmt.Println(value) // 这里会阻塞,因为通道是空的,缓冲区是空的 }
-
数组、
string
、slice
、map
、channel
等都可以使用for-range
语句遍历。其中channel
没有key
且阻塞。 -
闭包
package mainimport "fmt"func main() {var funcs []func() // 定义一个函数切片for i := 0; i < 3; i++ {funcs = append(funcs, func() { // 向切片添加匿名函数fmt.Println(i)})}for _, f := range funcs {f() // 输出: 3 3 3} }
-
4.3特殊控制语句
4.3.1defer
-
defer语句用于操作延迟到函数结束执行
-
defer语句将操作压栈,在结束时逆序执行
-
defer语句必须使用函数
-
格式
defer <functionCall>
-
示例
package mainfunc test() {defer println("test")println("hello") }func main() {test() // hello test }
-
4.3.2特殊使用
-
引用
谈及 defer 原理,defer 语句将延迟操作压栈,压栈数据包括:函数名、函数参数(临时)地址。后面的所有怪用都基于这一原理,defer 语句可以修改和访问本该已卸载的内存。defer 压栈后实际对地址又进行了一次引用,因此 Golang 的垃圾回收机制(GC)实际没有卸载这些内存。
-
修改函数的返回值
package mainfunc Demo() (s string) {s = "hello"defer func() { s = "world" } ()return s }func main() {println(Demo()) // world }
-
循环延迟返回相同返回值
func Demo1() {for i := 0; i < 3; i++ {defer fmt.Println(i)} } // 3 // 3 // 3 // 闭包 func Demo2() {for i := 0; i < 3; i++ {i := idefer fmt.Println(i)} } // 0 // 1 // 2
4.3.3go语句
-
go
语句将创建一个gorountine
,可以简单认为是一个线程或协程。go
语句的对象是一个函数,将函数作为一个新的线程运行。package mainimport ("fmt""time" )func thread() {for i := 0; i < 5; i++ {fmt.Println("Thread", i)time.Sleep(time.Microsecond * 50)} }func main() {go thread()for i := 0; i < 5; i++ {fmt.Println("Main", i)time.Sleep(time.Microsecond * 50)} }/* Main 0 Thread 0 Thread 1 Main 1 Main 2 Thread 2 Main 3 Thread 3 Thread 4 Main 4 */
- 多线程会使用,管道的读写需要配合创建线程使用
4.4异常处理
4.4.1panic&&recover
-
panic:抛出异常
-
recover:返回异常
package mainimport ("fmt" )func fn1() {panic("error") }func fn2() {fmt.Println("fn2") }func fn3() {defer func() {err := recover()if err != nil {fmt.Println(err)}}()panic("this is a error") }func main() {fn3() }
- 没有try catch,所以通过recover()来查看是否有异常抛出,来实现try catch的功能
- panic可以在任何地方用。而recover必须在defer里
4.4.2error
-
error接口原型
type error interface {Error() string }
-
构造异常,都是error类型
err := errors.New("异常信息") // error: "异常信息" err := fmt.Errorf("错误信息: %v", "异常信息") // errors.New(fmt.Sprintf(...))
-
类似于其它语言的try…catch
func myFn() {defer func() {err := recover()if err != nil {fmt.Println("给管理员发送邮件,得知错误")}}()err := readFile("xxx.go")if err != nil {panic(err)} }
-
示例
package mainimport ("fmt" )func readFile(filename string) error {if filename == "main.go" {return nil} else {// errors.New("异常信息")return fmt.Errorf("读取文件失败")} }func myFn() {defer func() {err := recover()if err != nil {fmt.Println("给管理员发送邮件,得知错误")}}()err := readFile("xxx.go")if err != nil {panic(err)} }func main() {myFn()fmt.Println("继续执行......") }
5.包管理
5.1包的分类
-
系统内置包:fmt、strings
-
自定义包:
-
小写的名称(包括方法和变量)代表私有,大写代表公有
-
直接import <路径>就可以使用
-
-
第三方包
- 下载
go get <地址>
或者import路径后使用go mod tity
下载使用未下载的包、删除未使用的包,后会出现sum.mod的文件
- 下载
5.2包管理工具go mod在·
go mod init <项目名称>
:初始化项目- 会生成go.mod文件
- 包名为 main 的包为应用程序的入口包,这种包编译后会得到一个可执行文件,而编译不包含 main 包的源代码则不会得到可执行文件!
- 别名,在前面写一个别名即可t “fmt”,在前面加_,命名为此,如果不使用不会报错
- 参考https://blog.csdn.net/TimeLies_Sea/article/details/131581569