前言
记录一些Go语言入门学习的基础知识
安装(Mac)
1 2
| brew install go brew upgrade go
|
Hello World
如在hello_world.go中添加如下代码
1 2 3 4 5 6 7 8
| package main
import "fmt"
func main() { fmt.Println("Hello, World!") }
|
在终端执行go run hello_world.go
,则会输出Hello, World!
执行流程,使用内置包(GoRoot)
去GoRoot中的src目录下去查找内置的包和函数,此处为fmt,然后就可以调用其中的方法了。其他的内置函数可以在GoRoot中src目录下进行查看,包含了crypto、errors、math、net等很多。
补充
GoRoot是go的安装目录,GoPath是Go的工作目录,可以通过命令go env
查看go的环境信息,我自己的如下:
1 2 3 4
| ... GOPATH="/Users/smiacter/go" GOROOT="/usr/local/Cellar/go/1.14.1/libexec" ...
|
使用github三方开源库(GoPath)
如果需要使用github三方库,则需要将包下载并安装到GoPath,获取三方开源库命令如下(go get xxx):
1
| go get github.com/gomodule/redigo/redis
|
上述命令会将包下载到GoPath下的src中,生成目录结构src/github.com/gomodule/redigo
补充
GoPath约定了三个目录,其作用分别如下:
src:存放源代码。按照 Go 语言约定,go run,go install 等命令默认会在此路径下执行
pkg:存放编译时生成的中间文件( * .a )
bin: 存放编译后生成的可执行文件
引用刚刚下载的三方库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package main
import ( "fmt" "github.com/gomodule/redigo/redis" ) func main() { c, err := redis.Dial("tcp", "127.0.0.1:6379") if err != nil { fmt.Println("Connect to redis error", err) return } fmt.Println("redis connect succ") defer c.Close() }
|
语法
基础数据类型(均是小写)
1 2 3 4
| 布尔值 - bool 整型 - int8 int16 int32 int64 (无符号整型 - uint8 uint 16 uint32 uint64) 浮点型 - float32 float64 字符串 - string
|
变量
go语言和Swift一样,是不用写 ; 的,巴适
1 2 3
| var name string name = "smiacter"
|
1 2 3 4
| var name = "smiacter"
name := "smiacter"
|
条件语句
1 2 3 4
| if name == "smiacter" { fmt.Println("yeah, it's me") }
|
1 2 3 4 5 6 7 8
| if statement ; condition { }
if a := 1 ; a < 10 { fmt.Println("a < 10") }
|
循环语句(只有for语句)
1 2 3 4
| for i := 0 ; i < 10 ; i++ { ... }
|
1 2 3 4
| for { server.Listen(8080) }
|
结构体【相当于class,go中没有class?】
1 2 3 4 5 6
| type Person struct { name string age int32 height float32 }
|
1 2 3 4 5 6
| person := new (Person)
person := &Person {name: "smiacter", age: 30, height: 173.1}
|
数据【感觉是指固定长度数组】
1 2 3 4 5 6 7
| var arr [100] string arr[0] = "smiacter" arr[1] = "yin"
var arr = [100]string{"smiacter", "yin"}
|
1 2 3 4 5 6 7 8 9 10
| for i := 0; i < 10; i++ { fmt.Println(arr[i]) }
for index, value := range arr { fmt.Println("index: %d, value: %s", index, value) }
|
切片【动态数组】
1 2 3 4
| var mArr []string
mArr = make([]string, "default_value")
|
1 2
| otherArr := []string{"111", "222", "333"}
|
常用方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| mArr = append(mArr, "new_string")
mArr[1:5] mArr[:3] mArr[3:]
len(mArr)
for i, value := range mArr { ... }
|
map
1 2 3 4 5 6 7 8
|
mMap := make(map[string]int32)
for key, value := range mMap { ... }
|
常用操作方法
1 2 3 4 5 6 7 8
| mMap[key] = value
value := mMap[key]
delete(mMap, key)
val, ok = mMap[key]
|
函数
1 2 3 4 5 6 7 8
| func func_name(p1 type, p2 type, ...) (return_type1, return_type2, ...) { }
func max(a int32, b int32) int32 { return a > b ? a : b }
|
方法【感觉是和Swift中接收指针的函数一样,go里面多了种叫法】
1 2 3 4 5 6 7 8 9 10 11 12 13
| func (p Pointer) func_name() return_type { }
func (p *Person) GetName() string { return p.name }
func (p *Person) SetName(name string) { p.name = name }
|
异常处理
使用error接口【抛出预期内的错误】
1 2 3 4 5 6 7 8 9 10 11
| type error interface { Error() string }
func check(isvalid bool) error { if !isvalid { return errors.New("不合法的参数") } }
|
使用defer语句
使用panic-recover 机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package main
import "fmt"
func main() { var a int var b int fmt.Println("请输入分子分母,以空格隔开,确定按回车键") fmt.Scanf("%d %d", &a, &b)
defer func() { if r := recover(); r != nil { fmt.Printf("panic的内容为:%v\n", r) } }()
rs := divide(a, b) fmt.Println("除法调用的结果为:", rs)
fmt.Println("发生了panic,这里还会执行吗") }
func divide(a int, b int) int { if b == 0 { panic("分母不能为0") } else { return a / b } }
|
面向对象
封装 【go中通过约定来实现权限控制】
- public - 变量和方法的首字母大写
- private - 变量和方法首字母小写
- go中没有继承,则无protected权限
继承
- go语言没有继承,可以通过在struct中包含其他struct,继承该包含struct的方法和变量,或者重写
多态
- 在go中,只要某个struct实现了某个interface的所有方法,那么我们认为这个struct实现了这个类
并发
go是一门天然支持高并发的语言
协程
go中的并发是以协程为基本粒度,类似其他语言中的线程。协程与线程是存在差别的,线程是内核态纬度的,利用CPU的中断机制进行线程切换。而协程是用户态纬度的,是一个特殊的函数,也可以中断执行。
并发
go中的并发正是通过协程实现并发的,并发中的每一个协程叫做goroutine, 其语法如下:
多个goroutine之间的消息通信方式,推荐使用channel,可以使用操作符<-
进行接收与发送值
1 2 3 4 5 6
| ch := make(chan int)
ch <- v
v := <-ch
|
1 2
| ch := make(chan int, 100)
|
select,使得一个 goroutine 在多个通讯操作上等待。select 会阻塞,直到条件分支中的某个可以继续执行,这时就会执行那个条件分支。当多个都准备好的时候,会随机选择一个。select 中的其他条件分支都没有准备好的时候,default 分支会被执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| func main() { tick := time.Tick(100 * time.Millisecond) boom := time.After(500 * time.Millisecond) for { select { case <-tick: fmt.Println("tick.") case <-boom: fmt.Println("BOOM!") return default: fmt.Println(" .") time.Sleep(50 * time.Millisecond) } } }
|
其他
- go中字符串使用双引号包裹,和Swift一样
- 变量和方法名遵守驼峰式命名
Slogan:
Confidence makes perfect!