Golang快速上手02/Golang基础
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 main func main() { a := 5 switch 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 := 90 switch { // 表达式 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 main import ( "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,开辟线程,去接受data go 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 default default 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 main import "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 main func test() { defer println("test") println("hello") } func main() { test() // hello test }
-
4.3.2特殊使用
-
引用
谈及 defer 原理,defer 语句将延迟操作压栈,压栈数据包括:函数名、函数参数(临时)地址。后面的所有怪用都基于这一原理,defer 语句可以修改和访问本该已卸载的内存。defer 压栈后实际对地址又进行了一次引用,因此 Golang 的垃圾回收机制(GC)实际没有卸载这些内存。
-
修改函数的返回值
package main func 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 := i defer fmt.Println(i) } } // 0 // 1 // 2
4.3.3go语句
-
go
语句将创建一个gorountine
,可以简单认为是一个线程或协程。go
语句的对象是一个函数,将函数作为一个新的线程运行。package main import ( "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 main import ( "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 main import ( "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