参考网站
征服之路
1、Go开发环境搭建
2、HelloWorld
3、变量的声明
4、常量的声明
5、多返回值函数
6、包制作与导包
7、指针
8、defer
9、数组和切片
10、map
11、面向对象
12、反射
13、并发: goroutine & channel
Go开发环境搭建
# download go-archive
$ wget https://golang.google.cn/dl/go1.17.7.linux-amd64.tar.gz
# Extract the archive you downloaded into /usr/local, creating a Go tree in /usr/local/go
$ sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.17.7.linux-amd64.tar.gz
# 配置GO相关环境变量
$ export GOROOT=/usr/local/go # 编译器安装目录
$ export GOPATH=$HOME/go # 放置Go代码的相关目录
$ export PATH=$PATH:$GOROOT/bin:$GOPATH/bin # 把上面的路径添加到PATH环境变量
# 验证是否安装成功
$ go version
go version go1.17.7 linux/amd64
HelloWorld
$ mkdir -p $GOPATH/src/helloworld && cd $GOPATH/src/helloworld
$ vim helloworld.go
// helloworld
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello World!")
}
$ go run helloworld.go
Hello World!
变量的声明
变量类型:
局部变量
全局变量
四种方式:
var a int
var b int = 1
var c = 1
d := 1 # 不支持全局变量
vi test.go
package main
import (
"fmt"
)
var a int
var b int = 1
var c = 1
func main() {
//只能在函数内定义, 在函数体外定义会报以下错误
// syntax error: non-declaration statement outside function body
d := 1
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
}
$ go run test.go
0
1
1
1
// 单行多变量声明
var b,c,d int = 1,1,1
var b,c,d = 1, true, "c"
// 多行多变量声明
var (
b int = 1
c bool
d string = "c"
)
常量的声明
const (
b int = 1
c bool = true
d string = "c"
)
func main(){
//d = 2 常量不可以再赋值,会报以下错误
//cannot assign to d (declared const)
}
// 关键字iota与常量的搭配使用
const (
b int = iota + 2 // iota = 0
c // iota = 1
d // iota = 2
)
2
3
4
const (
b, c int = iota + 2, iota + 3 // b, c = 0 + 2, 0 + 3
d, e
f, g
h, i = iota * 2, iota * 3 // h, i = 3 * 2, 3 * 3
j, k
l, m
)
2 3
3 4
4 5
6 9
8 12
10 15
多返回值函数
package main
import (
"fmt"
)
// 匿名写法
func f1() (int, int){
return 1, 1
}
// 显名写法
func f2() (i int, j int){
fmt.Println(i, j)
i, j = 1, 1
return i, j
}
// 半显半匿
func f3() (int, j int){
fmt.Println(j)
j = 1
return 1, j
}
func main() {
fmt.Println(f1())
fmt.Println(f2())
fmt.Println(f3())
}
$ go run test.go
1 1
0 0
1 1
0
1 1
包制作与导包
# 包制作
$ go env -w GO111MODULE=off
$ tree $GOPATH/src/pkg
$HOME/go/src/pkg
├── lib_1
│ └── main.go
└── lib_2
└── main.go
// ../lib_1/main.go
import (
"fmt"
)
func Test(){
fmt.Println("This is a Test function of lib_1...")
}
func init(){
fmt.Println("This is a init function of lib_1...")
}
// ../lib_2/main.go
package lib_2
import (
"fmt"
)
func Test(){
fmt.Println("This is a Test function of lib_2...")
}
func init(){
fmt.Println("This is a init function of lib_2...")
}
# 导包
$ vi test.go
package main
import (
//别名导包
mylib1 "pkg/lib_1"
mylib2 "pkg/lib_2"
)
func main() {
mylib1.Test()
mylib2.Test()
}
$ go run test.go
This is a init function of lib_1...
This is a init function of lib_2...
This is a Test function of lib_1...
This is a Test function of lib_2...
package main
import (
// 匿名导包, 无法使用当前包的方法, 但是会执行当前包内部的init方法
_ "pkg/lib_1"
mylib2 "pkg/lib_2"
)
func main() {
//mylib1.Test()
mylib2.Test()
}
$ go run test.go
This is a init function of lib_1...
This is a init function of lib_2...
This is a Test function of lib_2...
指针
package main
import (
"fmt"
)
func Vchange(i int){
i = 1
}
func Pchange(i *int){
*i = 1
}
func main() {
var a int
fmt.Println(a)
Vchange(a)
fmt.Println(a)
Pchange(&a)
fmt.Println(a)
}
$ go run test.go
0
0
1
defer
# 多函数弹栈式执行
$ vi deferFuns.go
// deferFuns.go
package main
import (
"fmt"
)
func fun1() {
fmt.Println("This is function 1...")
}
func fun2() {
fmt.Println("This is function 2...")
}
func fun3() {
fmt.Println("This is function 3...")
}
func main(){
defer fun1()
defer fun2()
defer fun3()
}
$ go run deferFuns.go
This is function 3...
This is function 2...
This is function 1...
# return、defer顺序执行
$ vi returnAndDefer.go
package main
import (
"fmt"
)
func retFuns() int{
fmt.Println("This is a return function...")
return 0
}
func deferFuns(){
fmt.Println("This is a defer function...")
}
func retAdef() int {
defer deferFuns()
return retFuns()
}
func main() {
retAdef()
}
$ go run returnAndDefer.go
This is a return function...
This is a defer function...
数组和切片
本人此前做过汇总介绍,此处不再赘叙,感兴趣跳转此页面了解详情
map
声明
package main
import(
"fmt"
)
func main() {
//第一种
var map1 map[int]string
fmt.Println(map1)
//使用前需用make分配数据空间
map1 = make(map[int]string)
map1[1] = "1"
fmt.Println(map1)
//第二种
map2 := make(map[int]string)
fmt.Println(map2)
map2[1] = "1"
fmt.Println(map2)
//第三种
map3 := map[int]string{1:"1"}
fmt.Println(map3)
}
$ go run src/test/map.go
map[]
map[1:1]
map[]
map[1:1]
map[1:1]
操作
package main
import(
"fmt"
)
func PrintMap(m map[int]string){
for k,v := range m {
fmt.Printf("%v: %v\n",k,v)
}
}
func main() {
map1 := map[int]string{
1:"one",
2:"two",
3:"three",
}
fmt.Println(map1)
//增加
map1[4] = "four"
fmt.Println(map1)
//修改
map1[2] = "2"
fmt.Println(map1)
//删除
delete(map1, 1)
fmt.Println(map1)
//遍历
PrintMap(map1)
}
$ go run src/test/map.go
map[1:one 2:two 3:three]
map[1:one 2:two 3:three 4:four]
map[1:one 2:2 3:three 4:four]
map[2:2 3:three 4:four]
2: 2
3: three
4: four
面向对象
封装
继承
多态
封装
切入点:
结构体
指针
函数
定义:
将某一类事物抽象成一个(属性、方法)的集合,该集合是一个模板,用于生成具有实际意义的对象
属性的集合-结构体
方法-指向结构体的指针的函数
package main
import (
"fmt"
)
//类,对象模板,属性和方法的集合
//定义属性
type Human struct {
sex string
age int
name string
}
// 定义方法
// 操作结构体的拷贝,假的类方法定义
func (this Human) setAge(a int){
this.age = a
}
// 操作结构体的引用,真的类方法定义
func (this *Human) setName(n string) {
this.name = n
}
func main() {
h1 := &Human{
sex: "man",
age: 18,
name: "lilei",
}
h2 := Human{
sex: "man",
age: 18,
name: "lilei",
}
//真假方法比较
fmt.Printf("Before: %v\n", h2.age)
h2.setAge(20)
fmt.Printf("After: %v\n", h2.age)
fmt.Printf("Before: %v\n", h1.name)
h1.setName("liming")
fmt.Printf("After: %v\n", h1.name)
}
$ go run Human.go
Before: 18
After: 18
Before: lilei
After: liming
继承
切入点:
子类继承父类的属性和方法
子类重写父类的方法
package main
import (
"fmt"
)
// 定义父类的属性和方法
type Human struct {
sex string
age int
name string
}
// 父类的方法
func (this *Human) Talk() {
fmt.Println("human can talk")
}
func (this *Human) Walk() {
fmt.Println("human can walk")
}
func (this *Human) Eat() {
fmt.Println("human can eat")
}
// 定义子类
type Spiderman struct{
Human // 继承父类
superpower string
}
// 重写父类的Walk方法
func (this *Spiderman) Walk(){
fmt.Println("Spiderman not only can walk, but also can climb to the top of building")
}
func main() {
// s := Spiderman{Human{"man",18,"peter"}, "spider-like power"}
var s Spiderman
s.sex = "man"
s.age = 18
s.name = "peter"
s.superpower = "spider-like power"
fmt.Println(s.superpower)
s.Talk()
s.Walk()
}
$ go run Spiderman.go
spider-like power
human can talk
Spiderman not only can walk, but also can climb to the top of building
多态
切入点:
接口 - 类的方法的模板,本质是一个指针
类中会具体地实现接口中的方法
package main
import(
"fmt"
)
// 接口Superman
type Superman interface {
fly()
run()
fight()
}
// 具体的类 Batman
type Batman struct {
ability string
}
func (this *Batman) fly(){
fmt.Printf("fly like a %v\n", this.ability)
}
func (this *Batman) run(){
fmt.Printf("run like a %v\n", this.ability)
}
func (this *Batman) fight(){
fmt.Printf("fight like a %v\n", this.ability)
}
// 具体的类 Spiderman
type Spiderman struct {
ability string
}
func (this *Spiderman) fly(){
fmt.Printf("fly like a %v\n", this.ability)
}
func (this *Spiderman) run(){
fmt.Printf("run like a %v\n", this.ability)
}
func (this *Spiderman) fight(){
fmt.Printf("fight like a %v\n", this.ability)
}
// 多态的例子
func InfoAbility(s Superman){
s.fly()
s.run()
s.fight()
}
func main(){
// var s Superman
// s = &Batman{"bat"}
// s.fly()
// s.run()
// s.fight()
// s = &Spiderman{"spider"}
// s.fly()
// s.run()
// s.fight()
InfoAbility(&Batman{"bat"})
InfoAbility(&Spiderman{"spider"})
}
$ go run interface.go
fly like a bat
run like a bat
fight like a bat
fly like a spider
run like a spider
fight like a spider
interface{}是万能的数据类型
package main
import(
"fmt"
)
func showArg(arg interface{}){
fmt.Println(arg)
}
type example struct{
exp string
}
func main(){
e := example{"for example"}
showArg(e)
showArg("Hello world")
showArg(18)
}
$ go run interface.go
{for example}
Hello world
18
反射
interface{}是万能的数据类型
package main
import(
"fmt"
)
func main(){
var a string
a = "bcd"
var b interface{}
b = a
var c int
c = 1
str, err := b.(string)
fmt.Println(a)
fmt.Println(b)
fmt.Println(str, err)
b = c
i, err := b.(int)
fmt.Println(c)
fmt.Println(b)
fmt.Println(i, err)
}
$ go run test.go
bcd
bcd
bcd true
1
1
1 true
reflect包常用的两个函数
TypeOf
ValueOf
package main
import(
"fmt"
"reflect"
)
func reflectAnt(arg interface{}){
fmt.Println("type: ", reflect.TypeOf(arg))
fmt.Println("value: ", reflect.ValueOf(arg))
}
func main(){
a := 1
b := "abc"
c := 3.14
reflectAnt(a)
reflectAnt(b)
reflectAnt(c)
}
$ go run test.go
type: int
value: 1
type: string
value: abc
type: float64
value: 3.14
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, "Aceld", 18}
DoFiledAndMethod(user)
}
func DoFiledAndMethod(input interface{}) {
//获取input的type
inputType := reflect.TypeOf(input)
fmt.Println("inputType is :", inputType.Name())
//获取input的value
inputValue := reflect.ValueOf(input)
fmt.Println("inputValue is:", inputValue)
//通过type 获取里面的字段
//1. 获取interface的reflect.Type,通过Type得到NumField ,进行遍历
//2. 得到每个field,数据类型
//3. 通过filed有一个Interface()方法等到 对应的value
for i := 0; i < inputType.NumField(); i++ {
field := inputType.Field(i)
value := inputValue.Field(i).Interface()
fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value)
}
//通过type 获取里面的方法,调用
for i := 0; i < inputType.NumMethod(); i++ {
m := inputType.Method(i)
fmt.Printf("%s: %v\n", m.Name, m.Type)
}
}
$ go run test.go
inputType is : User
inputValue is: {1 Aceld 18}
Id: int = 1
Name: string = Aceld
Age: int = 18
Call: func(main.User)
package main
import (
"fmt"
"reflect"
)
type resume struct {
Name string `info:"name" doc:"我的名字"`
Sex string `info:"sex"`
}
func findTag(str interface{}) {
t := reflect.TypeOf(str).Elem()
for i := 0; i < t.NumField(); i++ {
taginfo := t.Field(i).Tag.Get("info")
tagdoc := t.Field(i).Tag.Get("doc")
fmt.Println("info: ", taginfo, " doc: ", tagdoc)
}
}
func main() {
var re resume
findTag(&re)
}
$ go run test.go
info: name doc: 我的名字
info: sex doc:
并发: goroutine & channel
切入点:
进程、线程
goroutine
channel
进程、线程
进程看作资源空间,存放程序运行时需要的一切资源(如上图所示包括但不限的内存地址空间、文件和设备的句柄、线程)
线程看作执行空间,执行加载到内存中的主函数或是程序的某一段代码
goroutine
...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。