GO速成篇
11views
var a int = 1
var b int
c := 3 // 只能用在函数内部,无法定义全局变量
var d = 4
fmt.Println(a, b, c, d)
const length int = 10
const (
BEIJING = iota
SHANGHAI
SHENZHEN
)
fmt.Println(BEIJING, SHANGHAI, SHENZHEN)
const (
a, b = iota + 1, iota + 2 // iota = 0, a = 1, b = 2
c, d // iota = 1, c = 2, d = 3
e, f // iota = 2, e = 3, f = 4
g, h = iota * 2, iota * 3 // iota = 3, g = 6, h = 9
i, j // iota = 4, i = 8, j = 12
)
func fool(a int, b int) int {
return a + b
}
func Fool(a int, b int) int {
return a + b
}
// 指定返回参数,return跟空就行
func fool3(a string, b int) (r1 int, r2 int) {
r1 = 2000
r2 = 3000
return
}
func fool4(a int, b int) (r1, r2 int, r3 string) {
r1 = a + b
r2 = a - b
r3 = "hello"
return
}
func main() {
foox := func() {
fmt.Println("foo2")
}
fool(d, e)
foox()
}
// _ 解决导入但不使用,例如需要其init方法
// . 是直接调用:Test()
import (
. "./lib2"
_ "./lib3"
lib4 "./libFourTooLongLibName"
)
lib4.Test()
package main
import (
"fmt"
)
func changeValue(a *int) {
*a = 100
}
func main() {
a := 10
changeValue(&a)
fmt.Println("a = ", a)
}
&a
相当于获取a的地址。
a *int
在内存中存储的是a的地址,非变量值,相当于a = &a
。
*a = 100
相当于找到a存储的内存地址其对应的内存地址,将其赋值100
, *a
就是一个指针,有指向另一个的作用。
函数在结束之前再触发。
defer
用于延迟函数或方法的执行,主要用于需要在函数执行结束时进行一些清理操作或资源释放等场景。
资源清理:
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Create("test.txt")
if err != nil {
fmt.Println("Create file error:", err)
return
}
defer file.Close() // 确保在函数结束时关闭文件
fmt.Fprintf(file, "Hello, World!")
}
事务:
package main
import (
"database/sql"
"fmt"
)
func doTransaction(db *sql.DB) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer func() {
if err != nil {
tx.Rollback() // 如果出现错误,回滚事务
} else {
tx.Commit() // 如果没有错误,提交事务
}
}()
// 进行事务操作
_, err = tx.Exec("INSERT INTO table (column) VALUES ('value')")
return err
}
后进先出(LIFO)的顺序执行。
defer fmt.Println("Defer 1")
defer fmt.Println("Defer 2")
输出:
// Defer 2
// Defer 1
return先于return
package main
import "fmt"
func main() {
returnAndDefer();
}
func returnAndDefer() int {
defer deferFunc();
return returnFunc();
}
func deferFunc() int {
fmt.Println("deferFunc")
return 2
}
func returnFunc() int {
fmt.Println("returnFunc")
return 1
}
输出:
returnFunc
deferFunc
var arr [10]int;
arr[2] = 66;
arr2 := [4]int{1, 2, 3, 4};
// 局限,且也是值拷贝,例如arr[2] = 4不会改变外面值
// 切片是引用传递
func printArray(arr [4]int) {
for i, v := range arr {
fmt.Println(i, v)
}
}
// 1.声明且初始化
slice1 := []int{1, 2, 3, 4, 5}
// 2.声明,但未分配空间
var slice2 []int
// 3.make 开辟10个空间,默认为0
slice3 := make([]int, 10)
// 4.make 开辟10个空间,填充值为20
slice4 := make([]int, 10, 20)
// 5.声明且初始化, 下标1和2的值为100和200
slice5 := []int{1: 100, 2: 200}
// 引用传递
func main() {
myArray := []int{1, 2, 3, 4, 5}
printArray(myArray)
for i, v := range myArray {
fmt.Println(i, v)
}
}
func printArray(myArray []int) {
myArray[0] = 100
for _, v := range myArray {
fmt.Println(v)
}
}
打印结果:
100
2
3
4
5
0 100
1 2
2 3
3 4
4 5
cap: 容量:
var numbers = make([]int, 3, 5) // cap:5
fmt.Printf("len = %d, cap = %d, slice = %v", len(numbers), cap(numbers), numbers)
// 输出
// len = 3, cap = 5, slice = [0 0 0]%
如果cap满了,再开辟之前的cap量,如果未指定,则是之前的len,大概是这样。
// 1
var myMap map[string]string
myMap = make(map[string]string, 10)
myMap["no1"] = "宋江"
myMap["no2"] = "吴用"
myMap["no3"] = "卢俊义"
// 2
myMap2 := make(map[string]string)
myMap2["no1"] = "宋江"
myMap2["no2"] = "吴用"
myMap2["no3"] = "卢俊义"
// 3
myMap3 := map[string]string{
"no1": "宋江",
"no2": "吴用",
"no3": "卢俊义",
}
使用方式:
// 引用传递,可以修改
func printMap(myMap map[string]string) {
myMap["no4"] = "林冲"
}
// 遍历
for k, v := range myMap3 {
fmt.Printf("key = %v, value = %v\n", k, v)
}
// 删除
delete(myMap3, "no1")
// 修改
myMap3["no2"] = "吴用2"
// 查找
value, ok := myMap3["no3"]
if ok {
fmt.Printf("value = %v\n", value)
}
type:
type CityCode int
struct:
package main
import "fmt"
// 类名首字母大写,其他包也可以访问
// 类的属性名大些,该属性能对外访问,否则只能类内部访问
type Book struct {
title string
author string
}
func changeBook(book Book) {
// 传递的book的副本
book.title = "红楼梦"
}
func changeBook2(book *Book) {
// 传递的book的指针
book.title = "红楼梦"
}
func printBook(book Book) {
fmt.Printf("book: %v\n", book)
}
func main() {
var book1 Book
book1.title = "Go语言"
book1.author = "张三"
printBook(book1)
changeBook(book1)
printBook(book1)
changeBook2(&book1)
printBook(book1)
}
输出:
book: {Go语言 张三}
book: {Go语言 张三}
book: {红楼梦 张三}
package main
import "fmt"
type Hero struct {
Name string
Age int
Level int
}
func (this Hero) Show() {
// 这里this是值传递,不是引用传递,所以不会改变hero的值
fmt.Println("name = ", this.Name)
fmt.Println("age = ", this.Age)
fmt.Println("level = ", this.Level)
}
// this 可以取其他名,比如hero、t
func (this *Hero) GetName() string {
return this.Name
}
func (this *Hero) SetName(name string) {
this.Name = name
}
func main() {
hero := Hero{
Name: "宋江",
Age: 30,
Level: 1,
}
hero.SetName("吴用")
fmt.Println(hero.GetName())
}
package main
import "fmt"
type Human struct {
Name string
Age int
Sex string
}
type Hero struct {
Human // 继承
Level int
}
func (this *Human) Eat() {
fmt.Println("Human eat")
}
func (this *Human) Walk() {
fmt.Println("Human walk")
}
// ===============================
// 重定义父类的方法
func (this *Hero) Eat() {
fmt.Println("Hero eat")
}
func (this *Hero) Walk() {
fmt.Println("Hero walk")
}
// 子类新方法
func (this *Hero) Fly() {
fmt.Println("Hero fly")
}
func main() {
human := Human{
Name: "宋江",
Age: 30,
Sex: "男",
}
human.Eat()
human.Walk()
// hero := Hero{Human: human, Level: 1}
var hero Hero
hero.Name = "关羽"
hero.Age = 20
hero.Sex = "男"
hero.Level = 1
hero.Eat() // 子类的方法
hero.Walk() // 子类的方法
hero.Fly() // 子类的方法
}
package main
import "fmt"
// 本质是一个指针
type AnimalIF interface {
Sleep()
GetColor() string
GetType() string
}
type Cat struct {
color string
}
// 隐藏继承,要实现接口的所有方法才算实现
func (this *Cat) Sleep() {
fmt.Println("Cat sleep")
}
func (this *Cat) GetColor() string {
return this.color
}
func (this *Cat) GetType() string {
return "Cat"
}
type Dog struct {
color string
}
func (this *Dog) Sleep() {
fmt.Println("Dog sleep")
}
func (this *Dog) GetColor() string {
return this.color
}
func (this *Dog) GetType() string {
return "Dog"
}
func showAnimal(animal AnimalIF) {
animal.Sleep()
animal.GetColor()
animal.GetType()
}
func main() {
// 第一种
// var animal AnimalIF
// animal = &Cat{color: "yellow"}
// animal.Sleep()
// animal.GetColor()
// animal.GetType()
// animal = &Dog{color: "black"}
// animal.Sleep()
// animal.GetColor()
// animal.GetType()
cat := Cat{color: "yellow"}
dog := Dog{color: "black"}
// 第二种
showAnimal(&cat)
showAnimal(&dog)
}
通用万能类型:
interface{}
func myFunc(arg interface{}) {
fmt.Println("myFunc")
fmt.Println(arg)
}
func myFunc(arg interface{}) {
fmt.Println("myFunc")
fmt.Println(arg)
value, ok := arg.(int)
if !ok {
fmt.Println("arg is not int")
} else {
fmt.Println("arg is int", value)
}
}
极其晦涩难懂。
动态获取变量的pair 的 type value。
package main
import (
"fmt"
"reflect"
)
func main() {
var num float64 = 1.2345
reflect.TypeOf(num)
reflect.ValueOf(num)
var str string = "hello"
reflect.TypeOf(str)
reflect.ValueOf(str)
fmt.Println(reflect.TypeOf(num))
fmt.Println(reflect.ValueOf(num))
}
package main
import (
"fmt"
"reflect"
)
type User struct {
Id int
Name string
Age int
}
func (this User) Call() {
fmt.Println("user is called")
fmt.Printf("%v\n", this)
}
func main() {
user := User{1, "Allen.Wu", 25}
user.Call()
DoFileAndMethod(user)
}
func DoFileAndMethod(input interface{}) {
// 获取input的type
inputType := reflect.TypeOf(input)
fmt.Println("inputType is :", inputType)
// 获取input的value
inputValue := reflect.ValueOf(input)
fmt.Println("inputValue is :", inputValue)
// 通过type获取里面的字段
for i := 0; i < inputType.NumField(); i++ {
field := inputType.Field(i)
value := inputValue.Field(i).Interface()
fmt.Printf("field %d: name is %v, type is %v, value is %v\n", i, field.Name, field.Type, value)
}
// 通过type获取里面的方法,调用
for i := 0; i < inputType.NumMethod(); i++ {
method := inputType.Method(i)
fmt.Printf("method %d: name is %v, type is %v\n", i, method.Name, method.Type)
}
}
package main
import (
"fmt"
"reflect"
)
type resume struct {
Name string `info:"name" doc:"我的名字"`
Sex string `info:"sex" doc:"我的性别"`
}
func findTag(input interface{}) {
t := reflect.TypeOf(input).Elem()
for i := 0; i < t.NumField(); i++ {
tagstring := t.Field(i).Tag.Get("info")
fmt.Println("info is :", tagstring)
}
}
func main() {
var re resume
findTag(&re)
}
package main
import (
"encoding/json"
"fmt"
)
type Movie struct {
Title string `json:"title"`
Year int `json:"year"`
Price int `json:"rmb"`
Actors []string `json:"actors"`
}
func main() {
movie := Movie{"喜剧之王", 2000, 10, []string{"周星驰", "吴君如"}}
jsonStr, err := json.Marshal(movie)
if err != nil {
fmt.Println("json marshal error:", err)
}
fmt.Printf("jsonStr is %s\n", jsonStr)
}
线程/进程的数量越多,切换成本就越大,也就越浪费。
多线程随着同步竞争(如 锁、竞争资源冲突等)
package main
import (
"fmt"
"time"
)
func newTask() {
i := 0
for {
i++
fmt.Printf("new goroutine, i = %d\n", i)
time.Sleep(1 * time.Second)
}
}
func main() {
// 创建一个goroutine
go newTask()
i := 0
for {
i++
fmt.Printf("main goroutine, i = %d\n", i)
time.Sleep(1 * time.Second)
}
}
输出:
main goroutine, i = 1
new goroutine, i = 1
new goroutine, i = 2
main goroutine, i = 2
main goroutine, i = 3
new goroutine, i = 3
new goroutine, i = 4
main goroutine, i = 4
new goroutine, i = 5
main goroutine, i = 5
^Csignal: interrupt
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
go func() {
defer fmt.Println("A.defer")
func() {
defer fmt.Println("B.defer")
// 提前退出
runtime.Goexit()
fmt.Println("B")
}()
fmt.Println("A")
}()
for {
time.Sleep(1 * time.Second)
}
}
goroutine之间通信。
package main
import "fmt"
func main() {
// 定义channel
c := make(chan int)
go func() {
defer fmt.Println("goroutine 结束")
fmt.Println("goroutine 正在运行")
c <- 666 // 将666发送给channel
}()
num := <-c // 从channel中接收数据,赋值给num
fmt.Println("num = ", num)
fmt.Println("main goroutine 结束")
// 输出:
// goroutine 正在运行
// goroutine 结束
// num = 666
// main goroutine 结束
// channel 有阻塞的效果,强制顺序
}
谁先到谁阻塞,直到完成对接,双方释放。
图中对应,先放进去的人要一直保持到另一方进入并完成。
当channel已满,再向里面写数据就会阻塞。
当channel为空,从里面取数据也会阻塞。
package main
import (
"fmt"
"time"
)
func main() {
// 带有缓冲的channel, 3 是缓冲区的大小
c := make(chan int, 3)
fmt.Println("len(c) = ", len(c), "cap(c) = ", cap(c))
go func() {
defer fmt.Println("子go 结束")
for i := 0; i < 6; i++ {
c <- i
fmt.Println("子go 正在运行,发送的元素 = ", i, "len(c) = ", len(c), "cap(c) = ", cap(c))
}
}()
time.Sleep(2 * time.Second)
for i := 0; i < 6; i++ {
num := <-c // 从channel中接收数据,赋值给num
fmt.Println("num = ", num)
}
fmt.Println(("main 结束"))
// 输出
// len(c) = 0 cap(c) = 3
// 子go 正在运行,发送的元素 = 0 len(c) = 1 cap(c) = 3
// 子go 正在运行,发送的元素 = 1 len(c) = 2 cap(c) = 3
// 子go 正在运行,发送的元素 = 2 len(c) = 3 cap(c) = 3
// 子go 正在运行,发送的元素 = 3 len(c) = 3 cap(c) = 3
// num = 0
// num = 1
// num = 2
// num = 3
// num = 4
// 子go 正在运行,发送的元素 = 4 len(c) = 0 cap(c) = 3
// 子go 正在运行,发送的元素 = 5 len(c) = 0 cap(c) = 3
// 子go 结束
// num = 5
// main 结束
}
package main
import (
"fmt"
)
func main() {
c := make(chan int)
go func() {
for i := 0; i < 5; i++ {
c <- i
}
close(c)
}()
for {
if data, ok := <-c; ok {
fmt.Println("data = ", data)
} else {
break
}
}
// 输出:
// data = 0
// data = 1
// data = 2
// data = 3
// data = 4
}
package main
import (
"fmt"
)
func main() {
c := make(chan int)
go func() {
for i := 0; i < 5; i++ {
c <- i
}
close(c)
}()
// for {
// if data, ok := <-c; ok {
// fmt.Println("data = ", data)
// } else {
// break
// }
// }
// => 简写
for data := range c {
fmt.Println("data = ", data)
}
// 输出:
// data = 0
// data = 1
// data = 2
// data = 3
// data = 4
}
单流程下一个go只能监控一个channel的状态,select可以完成监控多个channel的状态。
select {
case <-ch1:
fmt.Println("ch1")
case ch2 <- 1:
fmt.Println("ch2")
default:
fmt.Println("default")
}
package main
import (
"fmt"
)
func fibonacci(c, quit chan int) {
x, y := 1, 1
for {
select {
case c <- x:
// 如果c可写,则将x的值赋给c
x = y
y = x + y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 6; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
Go Modules的目的之一就是淘汰GOPATH。
什么是GOPATH?
$ go env
GOPATH="/home/xxx/go"
GOPATH弊端:
常用:
env:
GOPROXY 设置代理。