GO入门指南实例
所属分类 go
浏览量 825
变量(Variable)
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
字符串
str := "hello"
fmt.Println(reflect.TypeOf(str).Kind()) // string
fmt.Println(reflect.TypeOf(str[0]).Kind()) // uint8
fmt.Println(str[0], string(str[0])) // 104 h
fmt.Printf("%d %c\n", str[0], str[0]) // 104 h
fmt.Println(len(str)) // 5
str1 := "GO语言"
fmt.Println(len(str1)) // 8
runeArr := []rune(str1)
fmt.Println(runeArr[2], string(runeArr[2])) // 35821 语
fmt.Println(len(runeArr)) // 4
reflect.TypeOf(xxx).Kind() 获取变量类型
字符串 byte数组
一个英文字符 1个字节 ,一个中文字符 一般 3个字节
将 string 转为 rune 数组 , 字符串中的每个字符 都用 int32 表示 ,4个字节
数组(array)与切片(slice)
数组长度不可变
切片使用数组作为底层结构 可自动扩展
切片3要素 容量 长度 和 指向底层数组的指针
声明切片时可设置容量大小 ,避免频繁扩容
var arr1 [3]int // 一维
var arr2 [2][3]int // 二维
var arr3 = [3]int{1, 2, 3}
fmt.Println(arr1) // [0 0 0]
fmt.Println(arr2) // [[0 0 0] [0 0 0]]
fmt.Println(arr3) // [1 2 3]
arr4 := [3]int{2,3,4}
fmt.Println(arr4) // [2 3 4]
for i := 0; i < len(arr4); i++ {
arr4[i] += 1
}
fmt.Println(arr4) // [3 4 5]
slice1 := make([]float32, 0) // 长度为0的切片
fmt.Println(slice1,len(slice1),cap(slice1))
slice2 := make([]float32, 3, 5) // [0 0 0] 长度3 容量5的切片
fmt.Println(len(slice2), cap(slice2)) // 3 5
// 添加元素,切片容量自动扩展
slice2 = append(slice2, 1, 2, 3) // [0, 0, 0, 1, 2, 3]
fmt.Println(len(slice2), cap(slice2)) // 6 12
// 子切片 [start, end)
sub1 := slice2[3:] // [1 2 3 ]
sub2 := slice2[:3] // [0 0 0]
sub3 := slice2[1:4] // [0 0 1]
fmt.Println(sub1,sub2,sub3)
// 合并切片
// sub2... 将切片解构为 N 个独立的元素
sub4 := append(sub1, sub2... ) // [1 2 3 0 0 0]
fmt.Println(sub4)
字典 键值对 map
map 类似于 java 的 HashMap,Python的字典(dict)
// 仅声明
m1 := make(map[string]int)
// 声明时初始化
m2 := map[string]string{
"a": "A",
"b": "B",
}
fmt.Println(m1,m2) // map[] map[a:A b:B]
// 赋值/修改
m1["a"] = 1
m2["a"] = "A2"
fmt.Println(m1,m2) // map[a:1] map[a:A2 b:B]
指针(pointer)
指针 变量地址
& 获取变量地址
str := "hello"
var p *string = &str
参数按值传递
函数内部 拷贝一份参数的副本,对副本的修改 不影响 原值
传递指针,直接操作指针指向的变量
func pointTest(){
str := "hello"
var p *string = &str
*p = "hello,go"
fmt.Println(str)
num := 1
// 值传递 函数内部修改的是副本 原值不变
add1(num)
fmt.Println(num) // 1
// 传地址 直接修改原值
add2(&num)
fmt.Println(num) // 2
}
func add1(num int) {
num += 1
}
func add2(num *int) {
*num += 1
}
流程控制(if, for, switch)
type 关键字定义 新类型
没有枚举(enum) 可用常量模拟
switch 不需要 break,匹配到某个 case,默认不会继续执行
如果需要继续往下执行,使用 fallthrough
for range 遍历 数组(arr) 切片(slice) 字典(map)
score := 90
if score < 60 {
fmt.Println("fail")
} else {
fmt.Println("success")
}
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")
}
sum := 0
i := 0
for ; i < 10; i++ {
if sum > 20 {
break
}
sum += i
// fmt.Println(i, sum)
}
fmt.Println(i, sum) // 7 21
nums := []int{10, 20, 30}
for i, num := range nums {
fmt.Print(i, num, " ")
}
fmt.Println()
m2 := map[string]string{
"a": "A",
"b": "B",
}
for key, value := range m2 {
fmt.Println(key, value)
}
函数(functions)
func funcName(param1 Type1, param2 Type2, ...) (return1 Type3, ...) {
// body
}
错误处理(error handling)
os.Open 2个返回值,*File 和 error
调用成功,error 为 nil
调用失败,例如文件不存在,可通过 error 获取具体错误信息
file, err := os.Open("file_not_exist.txt")
if err != nil {
// open file_not_exist.txt: no such file or directory
fmt.Println(err)
}
errorw.New 返回自定义错误
func newErrorTest() {
// fmt.Println(nameCheck(nil))
fmt.Println(nameCheck(""))
fmt.Println(nameCheck("xxx"))
fmt.Println(nameCheck("tiger"))
}
func nameCheck(name string) error {
if len(name) == 0 {
return errors.New("name is null")
}
if name == "xxx" {
return errors.New("name error")
}
fmt.Println("name=", name)
return nil
}
不可预知的错误,例如数组越界,导致程序非正常退出,称为 panic
panic 惊恐 恐慌
Java try catch 机制
Go defer 和 recover
defer 定义 异常处理的函数,退出前,执行 defer 注册的函数
如果触发了 panic,控制权 交给 defer
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{1, 2, 3}
return arr[index]
}
fmt.Println(get(0))
fmt.Println(get(7))
结构体(struct) 和 方法(methods)
结构体类似 Java中的 class,可以在结构体中定义字段和 方法,可 实例化
type Student struct {
name string
age int
}
func (student *Student) getName() string {
return student.name
}
func (student *Student) getInfo() string {
return fmt.Sprintf("name=%s,age=%d", student.name, student.age)
}
student := &Student{name: "tiger"}
fmt.Println(student.getName())
fmt.Println(student.getInfo())
student2 := &Student{name: "cat",age:7}
fmt.Println(student2.getInfo())
student3 := new(Student)
student3.name="dyyx"
student3.age=9
fmt.Println(student3.getInfo())
接口(interfaces)
type Person interface {
getName() string
}
接口 定义了一组方法的集合,接口不能被实例化,一个类型可以实现多个接口
不需要显式地声明实现了哪一个接口,实现接口对应的方法即可
Student 实现了 getName 方法 ,可转为 接口类型 Person
var _ Person = (*Student)(nil)
编译时检测
将空值 nil 转换为 *Student 类型,再转换为 Person 接口,
如果转换失败,说明 Student 并没有实现 Person 接口的所有方法
type Person interface {
getName() string
}
func interfaceTest() {
student := Student{name: "tiger"}
// main.Student
fmt.Println(reflect.TypeOf(student))
pointOfStudent := &student
// *main.Student
fmt.Println(reflect.TypeOf(pointOfStudent))
// 为啥这里不用 * ?
var person Person = &student
fmt.Println(reflect.TypeOf(person).Kind()) // ptr
// *main.Student
fmt.Println(reflect.TypeOf(person))
fmt.Println(person.getName())
student2 := person.(*Student)
fmt.Println(student2.getName())
var student3 *Student = &student
fmt.Println(student3.getName())
// 为啥这里不用
// var person2 *Person = &student
var person2 Person = &student
fmt.Println(person2.getName())
}
空接口 interface{} 可表示任何类型
m := make(map[string]interface{})
m["a"] = "hello"
m["b"] = 3
m["c"] = [3]int{1, 2, 3}
fmt.Println(m)
并发编程(goroutine)
提供 sync 和 channel 两种方式 支持协程(goroutine) 并发
并发下载 N 个资源,多个并发协程之间不需要通信,可使用 sync.WaitGroup,等待所有并发协程执行结束
sync.WaitGroup
var wg sync.WaitGroup
func download(url string) {
fmt.Println("start to download", url)
time.Sleep(time.Second) // 模拟耗时操作
// done 计数减1
wg.Done()
}
func waitGroupTest() {
for i := 0; i < 3; i++ {
// add 增加计数
wg.Add(1)
go download("http://codefun007.xyz/dl/" + string(i+'0'))
}
wg.Wait()
fmt.Println("all download Done!")
}
channel
var ch = make(chan string, 9) // 创建大小为 9 的缓冲信道
func downloadUseChannel(url string) {
fmt.Println("start to download", url)
time.Sleep(time.Second)
ch <- url // 将 url 发送给信道
}
func channelTest() {
for i := 0; i < 3; i++ {
go downloadUseChannel("http://codefun007.xyz/dl/" + string(i+'0'))
}
for i := 0; i < 3; i++ {
msg := <-ch // 等待信道返回消息
fmt.Println("download done", msg)
}
fmt.Println("all download use channel Done!")
}
单元测试(unit test)
add.go
package main
func add(a int,b int) int {
return a+b
}
add_test.go
package main
import "testing"
func TestAdd(t *testing.T) {
if result := add(1, 2); result != 3 {
t.Error("add(1, 2) should be equal to 3")
}
}
运行指定测试方法
go test -v -run TestAdd
=== RUN TestAdd
--- PASS: TestAdd (0.00s)
PASS
ok simplego 0.537s
https://gitee.com/dyyx/hellocode/blob/master/7days-golang/simpledemo/simplego/main.go
go http server
go基本语法例子
go程序设计语言01_05入门之获取URL
go程序设计语言01_06入门之并发获取多个URL
简洁的GO语言
GO多线程异步处理实例
go channel 实例
GO 并发递增计数实例
Go并发构建模块
Go语言atomic原子操作
GO mutex 与 atomic 性能对比
go defer 延迟函数
GO flag 命令行参数解析
GO panic recover
go socket 编程 echo server
GO文件读取
GO 面向对象编程
GO reflect
go httpFileServer
GO获取环境变量
上一篇
下一篇
go httpFileServer
temporal 任务运行机制实例测试
GO获取环境变量
temporal压测方案及记录
prometheus metrics 格式说明
httpclient 超时设置