Go 基础
Go 基础语法
Go 程序的入口的package 和函数名,必须都是 main。如果是一个包,包里函数小写开头,只能在这个包内使用,大写开头,则包内包外都可以使用。
循环
package main
import (
"fmt"
)
func main() {
for i := 1; i <= 9; i++ {
for j := 1; j <= i; j++ {
fmt.Printf("%d*%d=%d\t", j, i, i*j)
}
fmt.Println()
}
}
如果是字符串、数组、slice、map或 channel的遍历,可以用 range 来进行遍历
package main
import (
"fmt"
)
func main() {
str := "sdfajlskfa"
for i, c := range str {
fmt.Printf("%c", c)
fmt.Printf("%d,", i)
}
result1, result2 := add(2, 3)
fmt.Print(result1, result2)
}
func add(a, b int) (int, int) {
return a + b, a * b
}
如果是可变参数,可以在参数类型前加上 ...
package main
import (
"fmt"
)
func main() {
sum := 0
sum = getSum(1, 2, 3)
fmt.Println("sum result: ", sum)
}
func getSum(num ...int) int {
sum := 0
for i := 0; i < len(num); i++ {
sum += num[i]
}
return sum
}
可变参数也是支持不确定类型的参数,示例:
func printType(args ...interface{}) {
for _, arg := range args {
switch arg.(type) {
case int:
fmt.Println(arg, " type is int")
case string:
fmt.Println(arg, " type is string")
default:
fmt.Println(arg, " type is unknown")
}
}
}
如果是在一个list后面加 ... 则表示解序列,示例:
var s []string
s = append(s, []string{"a", "b", "c"}...)
fmt.Println(s)
数据类型:列表和切片
数组 array 和 slice 切片的区别: 数组是固定长度,slice是可变长度。如果改变了数组里的值,那实际上是修改的拷贝后的数组的值,原数组值不变。但如果改了slice的值,那么直接改变的就是原始slice。
arr := [4]int{1,2,3,4}
sli := []int{1,2,3,4}
匿名函数
直接 func() 不给函数起名,就是匿名函数,匿名函数也可以接受参数,也可以有返回值,一个示例:
r := func(a, b int) int {
return a + b
}(3, 5)
fmt.Println(r)
函数式编程
回调函数
将函数作为另外一个函数的参数,这个函数是回调函数,调用方是高阶函数。示例 add 就是回调函数
func main() {
addR := operator(3, 4, add)
fmt.Println(addR)
}
func operator(a, b int, f func(int, int) int) int {
r := f(a, b)
return r
}
func add(a int, b int) int {
return a + b
}
闭包
当内层函数使用外层函数的变量,外层函数销毁了,但内层函数还在执行,此时变量依然能用。这种结构就叫做闭包。在支持回调函数的程序语言里,一般都是支持闭包
值传递和引用传递
如果是值传递,那么传过去的函数里,拿到的是副本,对其修改不会作用到原来调用方。如果是引用传递,则传递过去的修改,会作用于本身。不过需要注意的是:如果在引用的函数里,对这个变量重新赋值,则即使是引用传递,也不会作用于原函数里。 值传递的数据类型: int、string、bool、float64、array 引用传递的数据类型: slice、map、chan
举一个例子:下面定义的 l1 是一个 slice(因为没有定义list长度),所以是引用传递。也就意味着,当在调用的函数里修改了这个值,则这个变量的内存地址里的值被修改,所以在原始main函数里,执行函数后的值也发生了变化
func main() {
l1 := []int{1, 2, 3, 4}
fmt.Println("传入前的值", l1)
updateList(l1)
fmt.Println("执行函数后的值", l1)
}
func updateList(l2 []int) {
fmt.Println("接收到的值\t", l2)
l2[0] = 100
fmt.Println("修改后的值\t", l2)
}
但同样的代码,我们把 l1 定义的时候,指定长度为4,定义为 array 列表,此时就是值传递,即使调用了某一个函数传了这个值,在调用函数内部做的修改,并不会反应到原始函数上。
func main() {
l1 := [4]int{1, 2, 3, 4}
fmt.Println("传入前的值", l1)
updateList(l1)
fmt.Println("执行函数后的值", l1)
}
func updateList(l2 [4]int) {
fmt.Println("接收到的值\t", l2)
l2[0] = 100
fmt.Println("修改后的值\t", l2)
}
package
如果包里的函数名是小写字母开头,只能在包内使用。
一个包内只能有一个 init() 函数,这个函数会在import的时候生效。
包是可以匿名导入的, 在匿名导入的时候,只会执行 init()函数。导入方法是
import _ packageName
在调用包的时候,可以给包起一个别名。如果别名是 . 则可以直接用这个包里的函数,比如 fmt.Println 如果import的时候别名是 . ,那么就可以直接用 Println()了,而不是 fmt.Println()
import (
. "fmt"
)
Go 模块下载
首先项目里要有 go.mod 文件,这个文件里包含了依赖包的信息,如果想要整理下这个文件,可以用 go mod tidy,会清理没用到的包。如果没有 go mod文件,可以初始化这个go项目。比如go代码都在当前路径的 my_project 文件夹下,那么我们用下面的命令,可以在该文件夹下创建 go.mod
go mod init my_project
之后下载包的时候用
go get github.com/ethereum/go-ethereum/crypto
最后更新于