# Go 语言学习
简单学习一下 go 语言,因为工作涉及,并且最近几年 go 语言发展比较快,用到的地方也比较多,不过更多都是用在 devops 相关业务上。
# 安装
安装比较简单啦,我用的是 windows,下载 amd64 的 msi 安装报直接安装即可,安装后会自动在系统高级环境设置中添加 go 的环境变量到 path 中,所以很简单。
# 简单程序示例
package main | |
import "fmt" | |
func main() { | |
fmt.Println("Hello World") | |
} | |
func init() { | |
fmt.Println("你好呀") | |
} |
这里做下解释:
- 定义当前程序的包的名字,如果想要写一个 go 文件并作为可运行的独立文件,必须要导入 main 包,不导入 main 包或者导入其他比如名字叫 mains 的包都会执行报错,这里执行指的是在 cmd 命令行下运行
go run hello.go
报错。每个 go 应用程序都包含一个名字叫 main 的包。 - 导入 fmt 包(或者函数啥的,也有可能是其他的),fmt 是我们在下面程序里需要用到的格式化输入、输出的函数。(也可以不导入包,直接使用
println("hello world")
) - main 是程序开始执行的函数,这个在各个语言中都差不多,main 函数是每个可执行程序都必须的,是程序的入口(一般来说,如果有 init 方法,会先执行 init 方法),init 函数和 main 函数有些差别,主要体现在使用上,可以自行百度。
- 注释很简单,略~~
- fmt.Println () 注意这里的 Println 函数的首字母是大写的 P,go 语言里如果函数、常量、变量等以大写字母开头,表示可以被外部包里的程序调用,相当于 java 里的 public 修饰符,如果第一个字母小写,相当于 java 里的 protect 修饰符(java 的默认修饰符),主要影响程序的调用和可见性。
- 程序可以直接使用
go run hello.go
运行得到输出,也可以先编译在运行,比如go build hello.go
windows 编译后会得到一个.exe 的可执行文件,然后.\hello.exe
执行,能够得到同样的输出。 - 同一个文件夹下面所有文件的 package name 必须是一样的(package name 不一定非得和文件夹名字一样),否则执行时会报错。
{
不能单独放在一行,会报:unexpected semicolon or newline before- 不建议使用省略调用,
import . "fmt"
# 导入自定义包
# 目录
--go-learning
----demo
------demo01.go
------demo02.go
----hello.go
## 代码 | |
/* hello.go */ | |
package main | |
import ( | |
"fmt" | |
math "./demo" | |
) | |
func main() { | |
fmt.Println("Hello World") | |
fmt.Println(math.Add(1, 1)) | |
fmt.Println(math.Sub(1, 1)) | |
} |
/* demo01.go */ | |
package math | |
func Add(x, y int) int { | |
return x + y | |
} | |
func div(x, y int) int { | |
return x / y | |
} |
/* demo02.go */ | |
package math | |
func Sub(x, y int) int { | |
var z = Add(2, 4) // 同文件夹内可直接调用 | |
var s = div(9, 3) | |
return x - y + z + s | |
} |
注意上面导入,Go 语言中,使用大小写来决定该常量、变量、类型、接口、结构或函数是否可以被外部包所调用。
- 函数名首字母小写即为 protect,仅包内部可调用
- 函数名首字母大写即为 public,包外部可调用
# 声明变量与格式化输出
package main | |
import ( | |
"fmt" | |
) | |
func main() { | |
var name = "jalen" | |
var age = 12 | |
var height = 178.23 | |
var total = fmt.Sprintf("name=%s; age=%d; height=%f", name, age, height) | |
fmt.Println(total) | |
} |
指定变量类型,如果没有初始化,则变量默认为零值。
零值就是变量没有做初始化时系统默认设置的值。
/* hello.go */ | |
package main | |
import ( | |
"fmt" | |
) | |
func main() { | |
var age int | |
fmt.Println(age) //0 | |
var name string | |
fmt.Println(name) //"" | |
var isStudent bool | |
fmt.Println(isStudent) //false | |
var pointer *int | |
fmt.Println(pointer) //<nil> | |
var array []int | |
fmt.Println(array) //[] | |
var mapString map[string]int | |
fmt.Println(mapString) //map[] | |
var socketChannel chan int | |
fmt.Println(socketChannel) //<nil> | |
var savePictureFunc func(string) int | |
fmt.Println(savePictureFunc) //<nil> | |
var errorInterface error | |
fmt.Println(errorInterface) //<nil> | |
} |
intVal := 1
相等于
var intVal int | |
intVal =1 |
注意值类型和引用类型以及它们在内存中分布的一些基本概念
int、float、bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值
变量声明后必须使用,否则报 unused 错误
值的交换, a, b = b, a
并行赋值, val, err = Func1(var1)
可以是用_表时抛弃值
# 数据类型
布尔型(true,false)、数字类型(int,float32,float64,complex)、字符串类型、派生类型。
派生类型包含:pointer、array、struct、channel、func、切片、interface、map
# 变量声明
var identifier type
/* hello.go */ | |
package main | |
import ( | |
"fmt" | |
math "./demo" | |
) | |
func main() { | |
fmt.Println("Hello World") | |
fmt.Println(math.Add(1, 1)) | |
fmt.Println(math.Sub(1, 1)) | |
var name string = "Jalen" | |
fmt.Println(name) | |
var age int = 12 | |
fmt.Println(age) | |
var username, password string = "Jalen", "@" | |
fmt.Println(username, password) | |
siteId, siteName := 12, "jalen.site" | |
fmt.Println(siteId, siteName) | |
a, b := 10, 20 | |
a, b = b, a | |
fmt.Println(a, b) | |
_, numb, strs := numbers() | |
fmt.Println(numb, strs) | |
} | |
func numbers() (int, int, string) { | |
a, b, c := 1, 2, "str" | |
return a, b, c | |
} |
# 常量声明
//const identifier [type] = value | |
const LENGTH int = 10 | |
const ( | |
Unknown = 0 | |
Female = 1 | |
Male = 2 | |
) | |
const ( | |
a = iota //=0 | |
b = iota //=1 | |
c = iota //=2 | |
) | |
const ( | |
a = iota //0 | |
b //1 | |
c //2 | |
d = "ha" // 独立值,iota += 1 | |
e //"ha" iota += 1 | |
f = 100 //iota +=1 | |
g //100 iota +=1 | |
h = iota //7, 恢复计数 | |
i //8 | |
) | |
const ( | |
a = 1 | |
b //=1 | |
c //=1 | |
d //=1 | |
) |
# 语言运算符
运算符和运算符优先级同其他语言基本相同,注意指针变量 * 与取地址赋值
/* hello.go */ | |
package main | |
func main() { | |
var a int = 4 | |
var ptr *int = &a | |
println("a的值为", a) // 4 | |
println("*ptr为", *ptr) // 4 | |
println("ptr为", ptr) // 824633794744 | |
} |
注意 a++ 和 a-- 这种自增自减运算不能用于赋值语句,只能作为表达式存在
/* hello.go */ | |
package main | |
func main() { | |
a++ // 这是允许的,类似 a = a + 1, 结果与 a++ 相同 | |
a-- // 与 a++ 相似 | |
a = a++ // 这是不允许的,会出现编译错误 syntax error: unexpected ++ at end of statement | |
} |
# 条件语句
- if
- if...else...
- if...else if...else...
- switch
- select
注意 Go 没有三目运算符,所以不支持?: 形式的条件判断。
select 比较新奇,随机执行一个可运行的 case,没有则阻塞挂起。
select { | |
case communication clause : | |
statement(s); | |
case communication clause : | |
statement(s); | |
/* 你可以定义任意数量的 case */ | |
default : /* 可选 */ | |
statement(s); | |
} |
# 循环语句
- break 中断(for、switch 中断)
- continue (跳过)
- goto (标记跳转)
# 语言函数
Go 语言最少有个 main () 函数。
func function_name( [parameter list] ) [return_types] {
函数体
}
# 遇到的问题
The term 'go' is not recognized as the name of a cmdlet, function, script file, or operable program 这个是 vscode 报错
我是先开的 vscode 写 go,写好后发现 go 环境没有安装,安装好 go 环境配置环境变量后重启 vscode 即可build command-line-arguments: cannot find module for path xxx 这个是新建文件夹,在文件夹下面新建了 2 个简单文件,然后从外部引入这个文件夹内的包,执行
go run hello.go
时报错,windows 在外部 cmd 下执行go env -w GO111MODULE=auto
(老版本可能是go env -w set GO111MODULE=auto
)