Go语言快速入门笔记01

语言特性

  1. 部署简单:
    1. 可直接编译成机器码执行
    2. 不依赖其他库
    3. 直接运行即可部署
  2. 静态类型语言:编译时即可检查出隐藏的问题
  3. 语言层面的并发:天生支持并发,充分利用多核
  4. 强大的标准库:
    1. runtime系统调度机制
    2. 高效的GC垃圾回收
    3. 丰富的标准库
  5. 简单易学:25个关键字,支持内嵌C语法,面向对象,跨平台
配置安装 Mac下载地址:https://dl.google.com/go/go1....
安装路径:/usr/local/go
配置环境变量:
vi ~/.bash_profile
export GOPATH=$HOME/go

source ~/.bash_profile
常见问题 1.go.mod file not found in current directory or any parent directory
解决:go env -w GO111MODULE=auto
语法注意
  1. 表达式结尾不建议加分号
  2. 导入多个包
    import ( "fmt" "time" )

  3. 函数的花括号必须与函数名同行
vim hello.go
package mainimport "fmt" func main() { fmt.Println("Hello Go!") }

编译并执行
go run hello.go

编译
go build hello.go

执行
./hello

变量 var
  1. 声明一个变量(默认值是0)
    var a int

  2. 声明一个变量,并初始化一个值
    var b int = 100

  3. 初始化时省去类型,通过值自动匹配数据类型(不推荐)
    var c = 100 var cc = "abcd"fmt.Printf("cc=%s,cc=%T",cc,cc)//cc=abcd,cc=string

  4. 省去var关键字,自动匹配(常用)
    e := 100 f := "abcd"

备注:方法1.2.3可以在函数体外,声明全局变量;4只能在函数体内,声明局部变量
  1. 声明多行变量
    var xx, yy int = 100, 200 var mm, nn = 100, "abc"var ( cc int = 100 dd bool = true ) fmt.Println("cc=",cc,"dd=",dd)

常量 const
常量是不允许修改的
const a int = 100 const ( BEIJING = 1 SHANGHAI = 2 )

iota:配合const使用,每行累加,第一行默认0
const ( BEIJING = 10 * iota //0 SHANGHAI//10 SHENZHEN//20 ) const ( a, b = iota+1,iota+2//iota=0, a=1, b=2 c, d//iota=1, c=1, d=3 g, h = iota*2,iota*3//iota=3, g=6, h=9 )

函数 基本函数形式
func test(a string, b int) int { return 100 }

多返回值
//匿名 func test(a string, b int) (int, int) { return 666, 777 } //有形参名(初始化默认为0) func test(a string, b int) (r1 int, r2 int) { r1 = 1000 r2 = 2000 return }

import与init Go语言快速入门笔记01
文章图片

hello.go
package main import ( "GoStudy/lib1" "GoStudy/lib2" ) func main() { lib1.Lib1Test(); //在外部调用的函数名首字母必须大写 lib2.Lib2Test(); } //输出结果 //lib1.init()... //lib2.init()... //Lib1Test()... //Lib2Test()...

lib1/lib1.go
package lib1 import "fmt" func Lib1Test(){ fmt.Println("Lib1Test()...") } func init(){ fmt.Println("lib1.init()...") }

lib2/lib2.go
package lib2 import "fmt" func Lib2Test(){ fmt.Println("Lib2Test()...") } func init(){ fmt.Println("lib2.init()...") }

注意:
  1. 导入匿名包(不执行包内的函数,但执行init方法)
    import _ "GoStudy/lib2"

  2. 导入包别名
    import l2 "GoStudy/lib2" func main() { l2.Lib2Test(); }

  3. 导入当前包中(可直接调用函数)
    import . "GoStudy/lib2" func main() { Lib2Test(); }

指针 *
package main import "fmt" func changeValue(p *int){ *p = 10; } func main() { var a = 1 changeValue(&a) //p = &a //*p = 10 fmt.Println("a =",a) //a = 10 }

defer
函数结束前执行的机制(先入后出,在return方法后执行)
package main import "fmt" func func1(){ fmt.Println("func1()...") } func func2(){ fmt.Println("func2()...") } func func3(){ fmt.Println("func3()...") } func returnAndDefer() int { defer func1() defer func2() defer func3() return returnFunc() } func returnFunc() int { fmt.Println("returnFunc()...") return 0 } func main() { returnAndDefer() } //执行顺序: returnFunc()... func3()... func2()... func1()...

数组与动态数组 固定长度的数组
package main import "fmt" func test(arr []int){ arr[0] = 111 } func main() { //固定长度的数组 var myArr []int //数组遍历 test(myArr)//myArr[0]不变 for k, v := range myArr2 { fmt.Println("index=",k,"value="https://www.it610.com/article/,v) } }

动态数组(切片 slice)
动态数组是引用传递,实际上传递的是数组的指针,指向同一块内存
不同长度的动态数组形参是一样的
package main import "fmt" func test(arr []int){ arr[0] = 111 } func main() { //固定长度的数组 myArr := []int{1,2,3,4} //数组遍历 test(myArr)//myArr[0]不变 for k, v := range myArr { fmt.Println("index=",k,"value="https://www.it610.com/article/,v) } } //输出结果 index= 0 value= 111 index= 1 value= 2 index= 2 value= 3 index= 3 value= 4

注:_表示匿名变量
切片的声明方式
  1. 【Go语言快速入门笔记01】声明slice1是一个切片,并且初始化,默认值是1,2,3,长度len是3
    slice1 := []int{1, 2, 3}

  2. 声明slice2是一个切片,但是并没有分配空间,需要make分配空间(初始化值是0)
    var slice2 = []int slice2 = make([]int, 3)

  3. 声明slice3是一个切片并通过make分配空间(初始化值是0)
    var slice3 []int = make([]int, 3)

  4. 声明slice4是一个切片并通过make分配空间(初始化值是0),通过:=推导出slice4是切片(常用)
    slice4 := make([]int, 3)

切片的追加 len:长度,表示左指针到右指针间的距离
cap:容量,表示左指针到底层数组末尾的距离
切片的扩容机制:append时,如果长度增加后超过容量,则将容量翻倍(5 -> 10 -> 20)
var numbers = make([]int, 3, 5)//长度3, 容量5 fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers) //len=3,cap=5,slice=[0 0 0]

向numbers追加一个元素1
numbers = append(numbers, 1) fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers) //len=4,cap=5,slice=[0 0 0 1]

向numbers追加一个元素2
numbers = append(numbers, 2) fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers) //len=5,cap=5,slice=[0 0 0 1 2]

向容量已满的slice追加元素
numbers = append(numbers, 3) fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers) //len=6,cap=10,slice=[0 0 0 1 2 3]

切片的截取
s := []int{1,2,3} s1 := s[0:2] s2 := make([]int, 3) copy(s2, s)//将s中的值,依次copy到s2 s1[0] = 100 fmt.Println(s)//[100 2 3] fmt.Println(s1)//[100 2] fmt.Println(s2)//[1 2 3]

map 声明方式
  1. 方式一:
    1. 声明myMap1是一种map类型,key是string,value是string
    2. 在使用map前,需要先用make给map分配数据空间
    var myMap1 map[string]string myMap1 = make(map[string]string, 10) myMap1["a"] = "aaa" myMap1["b"] = "bbb"

  2. 方式二:
    myMap2 := make(map[int]string) myMap2[0] = "a" myMap2[1] = "b" fmt.Println(myMap2) //map[0:a 1:b]

  3. 方式三
    myMap3 := map[int]string { 0 : "a", 1 : "b", } fmt.Println(myMap3) //map[0:a 1:b]

使用方式
map也是引用传递,做参数时传递的是指针地址
  1. 添加
    myMap2 := make(map[int]string) myMap2[0] = "a" myMap2[1] = "b"

  2. 遍历
    for k, v := range myMap2 { fmt.Printf("k=%d,v=%s\n",k,v) }

  3. 删除
    delete(myMap2, 0)

  4. 修改
    myMap2[0] = "c"

面向对象
结构体
  1. 定义
    type Book struct { title string //类的属性首字母大写表示公有,否则为私有 auth string }

  2. 使用
    var book1 Book book1.title = "Golang" book1.auth = "Tom" fmt.Println(book1)//{Golang Tom}book2 := Book{title:"aaa",auth:"bbb"} fmt.Println(book2)//{aaa bbb}book3 := Book{"aaa","bbb"} fmt.Println(book3)//{aaa bbb}

  3. 传递(传递的是副本)
    func changeBook(book Book){ book.title="XXX" } func main() { var book1 Book book1.title = "Golang" book1.auth = "Tom" changeBook(book1) fmt.Println(book1)//{Golang Tom} }

类 封装:类名,属性名,方法名首字母大写表示对外可以访问
this是调用该方法的对象的一个副本(拷贝)
func (this *Book) setName(title string){ this.title=title } func (this Book) setAuth(auth string){ this.auth=auth } func main() { book := Book{title:"aaa",auth:"bbb"} book.setName("ccc") book.setAuth("ddd") fmt.Println(book)//{ccc bbb} }

继承
package main import "fmt" type Human struct { name string sex string } type SuperMan struct { Human level int } func (this *Human) Eat(){ fmt.Println("Human Eat...") } func (this *Human) Walk(){ fmt.Println("Human Walk...") } func (this *SuperMan) Walk(){ fmt.Println("SuperMan Walk...") } func (this *SuperMan) Fly(){ fmt.Println("SuperMan Fly...") } func main() { tom := Human{"aaa","bbb"} tom.Eat() //Human Eat... tom.Walk()//Human Walk... //s :=SuperMan{Human{"ccc","ddd"},100} var s SuperMan s.name = "Sss" s.sex = "man" s.level= 88 s.Walk()//SuperMan Walk... s.Fly()//SuperMan Fly... }

多态
interface本质是父类的一个指针
基本要素:
  1. 有一个父类(接口)
  2. 有子类实现了父类的全部接口方法
  3. 父类类型的变量(指针)指向(引用)子类的具体数据变量
package main import "fmt" type AnimalIF interface { Sleep() GetColor() string } type Cat struct { color string } func (this *Cat) Sleep(){ fmt.Println("Cat Sleep...") } func (this *Cat) GetColor() string { return this.color } type Dog struct { color string } func (this *Dog) Sleep(){ fmt.Println("Dog Sleep...") } func (this *Dog) GetColor() string { return this.color } func showAnimal(animal AnimalIF){ animal.Sleep() fmt.Println("color=",animal.GetColor()) } func main() { var animal AnimalIF//接口的数据类型:父类指针 animal = &Cat{"White"} animal.Sleep()//Cat Sleep... fmt.Println("color=",animal.GetColor())//color= Whitedog := Dog{"Yellow"} showAnimal(&dog) //Dog Sleep... //color= Yellow }

万能数据类型 interface{} (空接口)
interface{} 类型断言机制:arg.(string)
package main import "fmt"type Book struct { tile string } func test(arg interface{}){ fmt.Println(arg) //断言 _, ok := arg.(string) if !ok { fmt.Println("arg is not string") }else{ fmt.Println("arg is string") } } func main() { book := Book{"Golang"} test(book)//{Golang} test(123)//123 test("hello")//hello }

变量类型
  1. 变量pair对
    1. type
      1. static type:int/string
      2. concrete type:interfece所指的具体数据类型(系统runtime看得见的类型)
    2. value
package main import "fmt" type Reader interface { ReadBook() } type Writer interface { WriteBook() } type Book struct {} func (this *Book) ReadBook() { fmt.Println("Read a book.") } func (this *Book) WriteBook() { fmt.Println("Write a book.") } func main() { b := &Book{}//b: pair var r Reader//r: pair r = b//r: pair r.ReadBook() var w Writer w = r.(Writer)//w: pair //断言有两步:得到动态类型 type,判断 type 是否实现了目标接口。 //这里断言成功是因为 type 是 Book,而 Book 实现了 Writer 接口 w.WriteBook() }

反射 reflect 例1:
package main import ( "fmt" "reflect" ) func reflectNum(arg interface{}){ fmt.Println("type:", reflect.TypeOf(arg)) fmt.Println("value:", reflect.ValueOf(arg)) } func main() { var num float64 = 1.34556 reflectNum(num) //type: float64 //value: 1.34556 }

例2:
package main import ( "fmt" "reflect" ) type User struct { Id int Name string Age int } func (this User) Call(){ fmt.Printf("User: %v", this) } func DoFieldAndMethod(input interface{}){ inputType := reflect.TypeOf(input) inputValue := reflect.ValueOf(input) //遍历属性 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) } //Id:int //Name:string = Lilei //Age:int = 18 //遍历方法(注意指针类型的结构体方法无法打印) for i := 0; i < inputType.NumMethod(); i++ { inputMethod := inputType.Method(i) fmt.Printf("%s:%v\n",inputMethod.Name, inputMethod.Type) } //Call:func(main.User) } func main() { user := User{1, "Lilei", 18} DoFieldAndMethod(user) }

结构体标签 Tag
package main import ( "fmt" "reflect" ) type User struct { Name string `info:"name" doc:"姓名"` Age int `info:"age" doc:"年龄"` } func findTag(input interface{}){ inputType := reflect.TypeOf(input).Elem() //遍历属性 for i := 0; i < inputType.NumField(); i++ { taginfo := inputType.Field(i).Tag.Get("info") tagdoc := inputType.Field(i).Tag.Get("doc") fmt.Printf("info:%s doc:%s\n",taginfo, tagdoc) } } func main() { var u User findTag(&u) //info:name doc:姓名 //info:age doc:年龄 }

结构体标签在json中的应用
package main import ( "fmt" "encoding/json" ) type User struct { Name string `json:"name"` Age int `json:"age"` Hobby []string `json:"hobby"` } func main() { user := User{"lilei", 18, []string{"dance","football"}} //json编码 jsonStr, err := json.Marshal(user) if err != nil { fmt.Println("Json marshal error.") return } fmt.Printf("json = %s",jsonStr)//json = {"name":"lilei","age":18,"hobby":["dance","football"]} //json解码 user1 := User{} err = json.Unmarshal(jsonStr, &user1) if err != nil { fmt.Println("Json unmarshal error.") return } fmt.Println(user1)//{lilei 18 [dance football]} }

    推荐阅读