首页  

GO 快速教程     所属分类 go 浏览量 650
Go是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。


package main
import "fmt"
func main() {
	fmt.Println("Hello World!")
}

go run main.go 或 go run .


go env -w GOPROXY=https://goproxy.cn,direct
go env -w GO111MODULE=on
auto 

go build main.go
./main 

var a int     // 没有赋值,默认为0
var a int = 1 // 声明时赋值
var a = 1     // 声明时赋值

a := 1
msg := "Hello World!"


简单类型 空值 nil 整型 int(取决于操作系统), int8, int16, int32, int64, uint8, uint16, … 浮点数 float32, float64 字节 byte (等价于uint8) 字符串 string 布尔值 boolean,(true 或 false) var a int8 = 10 var c1 byte = 'a' var b float32 = 12.2 var msg = "Hello World" ok := false 字符串 使用 UTF8 编码 英文,每个字符占 1 byte,和 ASCII 编码一样 节省空间 中文一般占3字节 package main import ( "fmt" "reflect" ) func main() { str1 := "Golang" str2 := "Go语言" fmt.Println(len(str1)) // 6 fmt.Println(len(str2)) // 8 fmt.Println(reflect.TypeOf(str2[2]).Kind()) // uint8 fmt.Println(str1[2], string(str1[2])) // 108 l fmt.Printf("%d %c\n", str2[2], str2[2]) // 232 è runeArr := []rune(str2) fmt.Println(len(runeArr)) // 4 fmt.Println(reflect.TypeOf(runeArr[2]).Kind()) // int32 fmt.Println(runeArr[2], string(runeArr[2])) // 35821 语 } reflect.TypeOf().Kind() 获取变量类型 字符串 byte 数组 中文处理 将 string 转为 rune 数组 rune 数组 字符串中的每个字符,用 int32 表示
数组(array)与切片(slice) var arr1 [2]int // 一维 var arr2 [2][3]int // 二维 fmt.Println(arr1) // [0 0] fmt.Println(arr2) // [[0 0 0] [0 0 0]] var arr3 = [3]int{1, 2, 3} for i := 0; i < len(arr3); i++ { arr3[i] += 10 } fmt.Println(arr3) // [11 12 13 ] 数组长度不可变 拼接2个数组,或 获取子数组,使用切片 切片是数组的抽象 ,使用数组作为底层结构 切片三要素 容量 长度和指向底层数组的指针 切片可以动态扩展 slice1 := make([]float32, 0) // 长度为0的切片 fmt.Println(len(slice1), cap(slice1), slice1) // 0 0 [] slice2 := make([]float32, 2, 3) // 长度为2容量为3的切片 fmt.Println(len(slice2), cap(slice2), slice2) // 2 3 [0,0] // 添加元素,自动扩展 slice2 = append(slice2, 1, 2, 3) fmt.Println(len(slice2), cap(slice2), slice2) // 5 6 [0 0 1 2 3] // 子切片 [start, end) sub1 := slice2[2:] // [1 2 3] sub2 := slice2[:2] // [0 0] sub3 := slice2[1:5] // [0 1 2 3] // [1 2 3 0 0] combined := append(sub1, sub2...) fmt.Println(sub1, sub2, sub3, combined) 声明切片时可设置容量大小,为切片预分配空间 ,容量会自动扩展 sub2... 是切片解构的写法,将切片解构为 N 个独立的元素
字典(键值对,map) map 类似 java HashMap,Python 字典(dict) // 仅声明 map1 := make(map[string]int) // 声明并初始化 map2 := map[string]string{ "A": "a", "B": "b", } map1["dyyx"] = 9 fmt.Println(map1, map2)
指针 pointer 指针即某个值的地址 类型定义时使用符号*,对一个已知的变量,使用 & 获取该变量的地址 str := "Golang" var pstr *string = &str *pstr = "Hello" fmt.Println(str) 指针的用途 函数传递参数 给某个类型定义新的方法 参数按值传递,如果不使用指针,函数内部将会拷贝一份参数的副本,对参数的修改并不会影响外部变量的值 func add(num int) { num += 1 } func realAdd(num *int) { *num += 1 } num := 8 add(num) fmt.Println(num) // 8 realAdd(&num) fmt.Println(num) // 9
流程控制(if, for, switch) score := 70 if score < 60 { fmt.Println("fail") } else { fmt.Println("pass") } type Gender int8 const ( MALE Gender = 1 FEMALE Gender = 2 ) gender := MALE switch gender { case FEMALE: fmt.Println("female") case MALE: fmt.Println("male") default: fmt.Println("unknown") } type 关键字定义新类型 没有枚举(enum) 用常量模拟 switch 不需要 break , 如果需要继续执行 ,使用 fallthrough sum := 0 for i := 0; i < 10; i++ { if sum > 50 { break } sum += i } for range 遍历 数组(arr) 切片(slice) 字典(map) nums := []int{10, 20, 30} for i, num := range nums { fmt.Println(i, num) } map3 := map[string]string{ "a": "A", "b": "B", } for key, value := range map3 { fmt.Println(key, value) }
函数(functions) func funcName(param1 Type1, param2 Type2, ...) (return1 Type3, ...) { // body } func func001(num1 int, num2 int) int { return num1 + num2 } func func002(num1 int, num2 int) (int, int) { return num1 / num2, num1 % num2 } value := func001(1, 2) fmt.Println(value) value1, value2 := func002(7, 3) fmt.Println(value1, value2) 给返回值命名,简化 return func func003(num1 int, num2 int) (result int) { result = num1 + num2 return } value3 := func003(2, 3)
错误处理(error handling) 标准库函数 os.Open 读取文件,2个返回值,第一个 *File,第二个 error 调用成功,error 的值是 nil 调用失败,例如文件不存在,error 错误信息 open file_not_exist.txt: no such file or directory _, err := os.Open("file_not_exist.txt") if err != nil { fmt.Println(err) } import errors errors.New 返回自定义的错误 func hello(name string) error { if len(name) == 0 { return errors.New("error: name is null") } fmt.Println("Hello,", name) return nil } fmt.Println(hello("")) fmt.Println(hello("dyyx")) error 一般是能预知的错误 一些不可预知的错误,例如数组越界,这种错误可能会导致程序非正常退出,称之为 panic func get(index int) int { arr := [3]int{2, 3, 4} return arr[index] } fmt.Println(get(5)) Java try catch 机制 Go 提供类似机制 defer 和 recover func get(index int) (ret int) { defer func() { if r := recover(); r != nil { fmt.Println("Some error happened!", r) ret = -1 } }() arr := [3]int{2, 3, 4} return arr[index] } fmt.Println(get(1)) fmt.Println(get(7)) get 函数中,使用 defer 定义 异常处理函数 在协程退出前,会执行完 defer 挂载的任务 如果触发了 panic,控制权就交给 defer 在 defer 的处理逻辑中,使用 recover,使程序恢复正常,并且将返回值设置为 -1, 如果不处理返回值,返回值将被置为默认值 0
结构体,方法和接口 type Student struct { name string age int } func (stu *Student) hello(person string) string { return fmt.Sprintf("hello %s, I am %s", person, stu.name) } student1 := &Student{ name: "dyyx", } fmt.Println(student1.hello("cat")) student2 := new(Student) fmt.Println(student2.hello("tiger")) 接口定义了一组方法的集合,接口不能被实例化,一个类型可以实现多个接口 type Person interface { getName() string } func (stu *Student) getName() string { return stu.name } type Worker struct { name string gender string } func (w *Worker) getName() string { return w.name } var person Person = &Student{ name: "dyyx", age: 18, } fmt.Println(person.getName()) (*Student).getName() 删掉 编译报错 *Student does not implement Person (missing getName method) 确保某个类型实现了某个接口的所有方法 var _ Person = (*Student)(nil) var _ Person = (*Worker)(nil) 接口强制类型转换为实例 student3 := person.(*Student) fmt.Println(student3) fmt.Println(student3.hello("codefun007.xyz")) 空接口 没有任何方法 ,可表示任意类型 map4 := make(map[string]interface{}) map4["name"] = "codefun007.xyz" map4["age"] = 5 map4["scores"] = [3]int{98, 99, 85} fmt.Println(map4)
并发编程(goroutine) Go 语言提供了 sync 和 channel 两种方式支持协程(goroutine)的并发 并发下载 N 个资源,多个并发协程之间不需要通信,使用 sync.WaitGroup,等待所有并发协程执行结束 var wg sync.WaitGroup func download(url string) { fmt.Println("start to download", url) time.Sleep(time.Second) // 模拟耗时操作 wg.Done() } for i := 0; i < 3; i++ { wg.Add(1) go download("http://codefun007.xyz/" + string(i+'0')) } wg.Wait() fmt.Println("Done!") wg.Add(1) 增加计数 wg.Done() 计数减一 go download() 启动新的协程并发执行 download 函数 wg.Wait() 等待所有的协程执行结束 var ch = make(chan string, 10) // 创建大小为 10 的缓冲信道 func download2(url string) { fmt.Println("start to download", url) time.Sleep(time.Second) ch <- url // 将 url 发送给信道 } for i := 0; i < 3; i++ { go download2("http://codefun007.xyz/" + string(i+'0')) } for i := 0; i < 3; i++ { msg := <-ch // 等待信道返回消息 fmt.Println("finish", msg) } fmt.Println("Done!") 使用 channel 信道,在协程之间传递消息 ,阻塞等待并发协程返回消息
单元测试(unit test) // calc.go package main func addForTest(num1 int, num2 int) int { return num1 + num2 } // calc_test.go package main import "testing" func TestAddForTest(t *testing.T) { if result := addForTest(1, 2); result != 3 { t.Error("add(1, 2) should be equal to 3") } } go test go test -v
包(Package)和模块(Modules) 一个文件夹可以作为 package // calc.go package main func add(num1 int, num2 int) int { return num1 + num2 } // main.go package main import "fmt" func main() { fmt.Println(add(3, 5)) // 8 } go run main.go 报错 undefined: add go run main.go calc.go go run . 包可见性 Public Private 类型/接口/方法/函数/字段 首字母大写, Public ,对其他 package 可见 首字母小写 Private ,对其他 package 不可见 Go Modules 是 Go 1.11 版本之后引入的,Go 1.11 之前使用 $GOPATH 机制 空文件夹,初始化一个 Module go mod init example 生成 go.mod 记录当前模块名以及所有依赖包的版本 import 模块名/子目录名
完整例子代码 https://gitee.com/dyyx/hellocode/blob/master/demo/go/goquick/main.go

上一篇     下一篇
GO操作Mysql

余杭护国山

职场暗语

go 数组和切片

高庄宸迹

go make 用法