语言个性

  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 = 100var cc = "abcd"fmt.Printf("cc=%s,cc=%T",cc,cc)//cc=abcd,cc=string
  4. 省去var关键字,主动匹配(罕用)

    e := 100f := "abcd"

备注:办法1.2.3能够在函数体外,申明全局变量;4只能在函数体内,申明局部变量

  1. 申明多行变量

    var xx, yy int = 100, 200var mm, nn = 100, "abc"var (    cc int = 100    dd bool = true)fmt.Println("cc=",cc,"dd=",dd)

常量 const

常量是不容许批改的
const a int = 100const (    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

hello.go

package mainimport (    "GoStudy/lib1"    "GoStudy/lib2")func main() {    lib1.Lib1Test();  //在内部调用的函数名首字母必须大写    lib2.Lib2Test();    }//输入后果//lib1.init()...//lib2.init()...//Lib1Test()...//Lib2Test()...

lib1/lib1.go

package lib1import "fmt"func Lib1Test()  {    fmt.Println("Lib1Test()...")}func init()  {    fmt.Println("lib1.init()...")}

lib2/lib2.go

package lib2import "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 mainimport "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 mainimport "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 mainimport "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=",v)    }}
动静数组(切片 slice)

动静数组是援用传递,实际上传递的是数组的指针,指向同一块内存

不同长度的动静数组形参是一样的

package mainimport "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=",v)    }}//输入后果index= 0 value= 111index= 1 value= 2index= 2 value= 3index= 3 value= 4

注:_示意匿名变量

切片的申明形式
  1. 申明slice1是一个切片,并且初始化,默认值是1,2,3,长度len是3

    slice1 := []int{1, 2, 3}
  2. 申明slice2是一个切片,然而并没有调配空间,须要make调配空间(初始化值是0)

    var slice2 = []intslice2 = 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, 容量5fmt.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到s2s1[0] = 100fmt.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]stringmyMap1 = 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 Bookbook1.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 mainimport "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 mainimport "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= White    dog := Dog{"Yellow"}    showAnimal(&dog)    //Dog Sleep...    //color= Yellow}
万能数据类型 interface{} (空接口)
interface{} 类型断言机制:arg.(string)
package mainimport "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 mainimport "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<type:Book, value:Book{}地址>    var r Reader//r: pair<type: 空, value: 空>    r = b       //r: pair<type:Book, value:Book{}地址>    r.ReadBook()    var w Writer      w = r.(Writer)//w: pair<type:Book, value:Book{}地址>    //断言有两步:失去动静类型 type,判断 type 是否实现了指标接口。    //这里断言胜利是因为 type 是 Book,而 Book 实现了 Writer 接口    w.WriteBook()}

反射 reflect

例1:

package mainimport (    "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 mainimport (    "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 mainimport (    "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 mainimport (    "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]}}