文章目录

  • 数组
  • 切片
    • append 函数
  • Map
  • 结构体
  • JSON

数组

  • 数组长度是固定

  • Go函数在接收参数时,接收的是参数的副本,所以不会改变原有参数值,在Python中把列表作为参数传递会改变原有列表的值,在Go中不会。

    如果想要改变原始的参数值,可以使用指针作为参数传递:

    func zero(ptr *[32]byte) {*ptr = [32]byte{}
    }
    

遍历数组

for i, v := range a {fmt.Printf("%d %d\n", i, v)
}// Print the elements only.
for _, v := range a {fmt.Printf("%d\n", v)
}

初始化

  • 数组的每个元素都被初始化为元素类型对应的零值,也可以使用数组字面值语法用一组值来初始化数组:

    var q [3]int = [3]int{1, 2, 3}
    var r [3]int = [3]int{1, 2}
    fmt.Println(r[2]) // "0"
    
  • 如果在数组的长度位置出现的是**“…”省略号**,则表示数组的长度是根据初始化值的个数来计算

    q := [...]int{1, 2, 3}
    fmt.Printf("%T\n", q) // "[3]int"
    
  • 数组的长度必须在定义的时候声明,因为数组的长度需要在编译阶段确定:

    q := [3]int{1, 2, 3}
    q = [4]int{1, 2, 3, 4} // compile error: cannot assign [4]int to [3]int
    
  • 使用key value形式初始化:

    type Currency intconst (USD Currency = iota // 美元EUR                 // 欧元GBP                 // 英镑RMB                 // 人民币
    )symbol := [...]string{USD: "$", EUR: "€", GBP: "£", RMB: "¥"}fmt.Println(RMB, symbol[RMB]) // "3 ¥"
    

数组比较

  • 如果数组类型是一样(包括元素类型和数组长度),那么这两个数组是可以比较的:

    a := [2]int{1, 2}
    b := [...]int{1, 2}
    c := [2]int{1, 3}
    fmt.Println(a == b, a == c, b == c) // "true false false"
    d := [3]int{1, 2}
    fmt.Println(a == d) // compile error: cannot compare [2]int == [3]int
    

切片

  • Go中的切片操作和Python中的差不多,但是Go中的切片有个cap容量的概念和len长度的概念:

    如定义一个12个元素的数组:

    months := [...]string{1: "January", /* ... */, 12: "December"}
    

    使用该数组的切片的最大容量就是13,该切片的最大长度就是13,如下定义了一个容量为7的切片(6到12的长度),长度为3:

    summer := months[6:9]
    

    当切片操作超出容量时就会报异常,但是超出长度,没超出容量就会扩展切片:

    // 下边切片长度为20,超出了summer切片底层数组的容量
    fmt.Println(summer[:20]) // panic: out of range// 下边切片长度为5,超出了summer切片的长度,但是没有超出summer底层数组的容量,会扩展切片
    endlessSummer := summer[:5] // extend a slice (within capacity)
    fmt.Println(endlessSummer)  // "[June July August September October]"
    
  • 切片只是对底层数组部分元素的引用,切片操作赋值给变量会生成新的数组,直接把切片作为参数传递给函数,可以在函数内部直接对底层数组进行操作

    // reverse reverses a slice of ints in place.
    func reverse(s []int) {for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {s[i], s[j] = s[j], s[i]}
    }
    
    a := [...]int{0, 1, 2, 3, 4, 5}
    reverse(a[:])
    fmt.Println(a) // "[5 4 3 2 1 0]"
    
  • 切片不能通过==直接判断是否相等

  • 长度或者容量为0的切片一定为nil,但是不为nil的切片长度也可能为0,所以不能通过是否等于nil来判断切片长度是否为空:

    var s []int    // len(s) == 0, s == nil
    s = nil        // len(s) == 0, s == nil
    s = []int(nil) // len(s) == 0, s == nil
    s = []int{}    // len(s) == 0, s != nil
    
  • 可以使用make创建匿名切片:

    // 如果不指定容量,默认容量和长度一样
    make([]T, len)make([]T, len, cap) // same as make([]T, cap)[:len]// 如果切片的容量是已知的创建时最好指定容量
    make([]string, 0, 5)
    

append 函数

  • 可以通过append函数向切片中增加元素:

    var runes []rune
    for _, r := range "Hello, 世界" {runes = append(runes, r)
    }
    fmt.Printf("%q\n", runes) // "['H' 'e' 'l' 'l' 'o' ',' ' ' '世' '界']"
    

    但是一定要将append结果赋值给原切片:

    package mainimport "fmt"func main()  {var runes []runevar new_runes []runefor _, r := range "HELLO" {runes = append(runes, r)}fmt.Printf("%q\n", runes) // 输出 ['H' 'E' 'L' 'L' 'O']fmt.Printf("%q\n", new_runes) // 输出 []
    }
    

    如果不赋值:

    package mainimport "fmt"func main()  {var runes []runevar new_runes []runefor _, r := range "HELLO" {new_runes = append(runes, r)}fmt.Printf("%q\n", runes) // 输出 []fmt.Printf("%q\n", new_runes) // 输出 ['O']
    }
    
  • append 也可以同时追加多个元素:

    var x []int
    x = append(x, 1)
    x = append(x, 2, 3)
    x = append(x, 4, 5, 6)
    x = append(x, x...) // append the slice x
    fmt.Println(x)      // "[1 2 3 4 5 6 1 2 3 4 5 6]"
    
  • 模拟stack:

    空栈

    stack := []int
    

    压栈

    stack = append(stack, v) // push v
    

    栈顶元素

    top := stack[len(stack)-1] // top of stack
    

    弹栈

    stack = stack[:len(stack)-1] // pop
    

Map

  • Go中的MapPython中的字典是一样的,Python字典中的key 要求为不可变类型,但是Go中的key 只要可以使用== 比较就行。
  • 不能对Map元素取址操作,因为元素并不是一个变量,而且如果Map扩容会导致元素地址重新分配。
  • map 和切片一样不能直接通过== 比较是否相等
  • map是无序的

创建

// 使用make创建
ages := make(map[string]int)
// 使用var 创建
var new_ages map[string]int
  • 在创建时也可以指定初始值:

    ages := map[string]int{"alice":   31,"charlie": 34,
    }
    
  • 在创建空map时如果没有初始化,创建完的map为nil类型, 长度为0

    ages := make(map[string]int)
    var new_ages map[string]int
    

    需要注意的是nil 类型的map 只能进行查询和删除,遍历操作,不能进行增改操作

    var nil_map map[string]int// 往使用var创建的nilmap中插入元素报错
    nil_map["zzy"] = 2 // panic: assignment to entry in nil map
    

新增

ages["alice"] = 31
ages["charlie"] = 34

删除

delete(ages, "alice")

查改

// 即使没有bob key 也不会报异常,而是返回对应value类型的0值
ages["bob"] = ages["bob"] + 1
ages["bob"] += 1
ages["bob"]++// 判断是不存在key 返回0还是本来就是0值:
ages := make(map[string]int)ages["zzy"] = 23_, ok_zzy := ages["zzy"]
_, ok_bob := ages["bob"]if !ok_zzy {fmt.Printf("%v:map不存在key为zzy", ok_zzy) // false:map不存在key为zzy
}
if !ok_bob {fmt.Printf("%v:map不存在key为bob", ok_bob)
}// if 可以简写:
if age, ok := ages["zzy"]; !ok {/*...*/}

遍历map

ages := make(map[string]int)ages["alics"] = 31
ages["Alics"] = 32var names []string
var age []int
for key, value := range ages {names = append(names, key)age = append(age, value)
}

自定义key

  • map 中的可以必须是可以比较类型,如果想使用切片或者其他不可比较类型作为key, 可以自定义函数,将该类型转换为同样含义的不可变类型,在作为key就可以了:

    var m = make(map[string]int)// 定义函数k 将切片类型转换为字符串类型作为key
    func k(list []string) string { return fmt.Sprintf("%q", list) }// 自定义一些需要根据key操作的函数
    func Add(list []string)       { m[k(list)]++ }
    func Count(list []string) int { return m[k(list)] }
    

结构体

结构体定义

  • 使用关键字typestruct
type Employee struct {ID        intName      stringAddress   stringDoB       time.TimePosition  stringSalary    intManagerID int
}var dilbert Employee
  • 一行定义一个类型,相同类型可以定义在同一行,但是通常只将相关的成员写到一起:
type Employee struct {ID            intName, Address stringDoB           time.TimePosition      stringSalary        intManagerID     int
}
  • 成员顺序不同,将是两个不同的结构体。

  • 成员名字大写表示公开的,小写表示私有的。

  • 结构体成员不能包含自身类型的成员,但可以包含自身指针类型的成员(用于递归)

  • 一个零值结构体的成员都是零值

  • 一个结构体相当于Python中的一个对象,使用结构体定义变量相当于实例化对象,可以通过实例化对象访问结构体中的属性,并且赋值。

    dilbert.Salary -= 5000
    
  • 通过指针访问:

    position := &dilbert.Position
    *position = "Senior " + *position
    

结构体字面值初始化

  • 根据成员位置初始化:

    package p
    type T struct{ A, B int }package q
    import "p"
    var _ = p.T{1, 2} // 一般像定义坐标点,像素这种成员位置不变的结构体使用这种方式初始化
    
  • 一般使用键值对方式初始化:

    package p
    type T struct{ A, b int }package q
    import "p"
    var _ = p.T{A: 1} // 需要注意的是b 为私有属性外部包无法访问,也不能进行初始化
    

定义函数返回结构体指针

  • 可以定义函数返回指向结构体的指针:

    func EmployeeByID(id int) *Employee { /* ... */ }fmt.Println(EmployeeByID(dilbert.ManagerID).Position) // "Pointy-haired boss"id := dilbert.ID
    EmployeeByID(id).Salary = 0 // fired for... no real reason
    

    如果将函数的从指针类型改为Employee值类型,将编译错误:EmployeeByID(id).Salary = 0(EmployeeByID(id).Salary不是一个变量,不能赋值)

结构体作为函数参数和返回值

func Scale(p Point, factor int) Point {return Point{p.X * factor, p.Y * factor}
}fmt.Println(Scale(Point{1, 2}, 5)) // "{5 10}"
  • 如果结构体较大,可以使用结构体指针作为参数:

    func Bonus(e *Employee, percent int) int {return e.Salary * percent / 100
    }
    
  • 如果要修改结构体成员的话,用指针传入是必须的(所有函数参数都是值拷贝传入,不是原始变量):

    func AwardAnnualRaise(e *Employee) {e.Salary = e.Salary * 105 / 100
    }
    

结构体比较

  • 和切片、map不同,如果结构体中的所有成员都是可以比较的,那么该结构体可以使用==比较:

    type Point struct{ X, Y int }p := Point{1, 2}
    q := Point{2, 1}
    fmt.Println(p.X == q.X && p.Y == q.Y) // "false"
    fmt.Println(p == q)                   // "false"
    
  • 可比较的结构体类型可以作为map的key:

    type address struct {hostname stringport     int
    }hits := make(map[address]int)
    hits[address{"golang.org", 443}]++
    

结构体嵌入和匿名成员

  • Go 虽然不是一个面向对象的语言,但是却保存了面向对象的优点,去除了面向对象继承的后遗症,因此引入了结构体嵌套的语法,来建立各个对象之间的联系。

  • 一个结构体可以引入另一个结构体:

    type Point struct {X, Y int
    }type Circle struct {Center PointRadius int
    }type Wheel struct {Circle CircleSpokes int
    }
    

    访问wheel 成员和嵌套结构体的成员:

    var w Wheel
    w.Circle.Center.X = 8
    w.Circle.Center.Y = 8
    w.Circle.Radius = 5
    w.Spokes = 20
    
  • 上边的嵌套方式在访问嵌套结构体成员的时候非常复杂,因此引入了匿名成员(只声明一个成员对应的数据类型而不指名成员的名字):

    type Circle struct {PointRadius int
    }type Wheel struct {CircleSpokes int
    }
    

    访问嵌套成员(可以直接访问嵌套成员,之前的访问方法还是成立的):

    var w Wheel
    w.X = 8            // equivalent to w.Circle.Point.X = 8
    w.Y = 8            // equivalent to w.Circle.Point.Y = 8
    w.Radius = 5       // equivalent to w.Circle.Radius = 5
    w.Spokes = 20
    
  • 结构体字面值不能使用简短方式初始化匿名成员:

    w = Wheel{8, 8, 5, 20}                       // compile error: unknown fields
    w = Wheel{X: 8, Y: 8, Radius: 5, Spokes: 20} // compile error: unknown fields
    

    可以通过以下方式初始化匿名成员:

    w = Wheel{Circle{Point{8, 8}, 5}, 20}w = Wheel{Circle: Circle{Point:  Point{X: 8, Y: 8},Radius: 5,},Spokes: 20, // NOTE: trailing comma necessary here (and at Radius)
    }
    

JSON

序列化

  • Go中的序列化叫做编组,使用json.Marshal函数:

    package mainimport ("encoding/json""fmt""log"
    )type Movie struct {Title   stringYear  int `json:"released"`  // 反引号括起来是结构体成员标签Color   bool `json:"color,omitempty"`Actors []string
    }var movies = []Movie{{Title: "Casablanca", Year: 1942, Color: false, Actors: []string{"Humph Boke", "Inge ZZ"}},{Title: "Casablanca", Year: 1942, Color: true, Actors: []string{"Humph Boke", "Inge ZZ"}},
    }func main() {data, err := json.Marshal(movies)if err != nil {log.Fatalf("JSON marshaling failed: %s", err)}fmt.Printf("%s\n", data)
    }
    

    使用上边函数结果是没有空白缩进的:

    [{"Title":"Casablanca","released":1942,"Actors":["Humph Boke","Inge ZZ"]},{"Title":"Casa
    blanca","released":1942,"color":true,"Actors":["Humph Boke","Inge ZZ"]}]
    
  • 使用json.MarshalIndent函数将产生整齐缩进的输出:

    data, err := json.MarshalIndent(movies, "*", "    ") // 参数:解析切片,前缀,缩进
    if err != nil {log.Fatalf("JSON marshaling failed: %s", err)
    }
    fmt.Printf("%s\n", data)
    

    结果:

    [
    *   {
    *      "Title": "Casablanca",
    *      "released": 1942,
    *      "Actors": [
    *         "Humph Boke",
    *         "Inge ZZ"
    *      ]
    *   },
    *   {
    *      "Title": "Casablanca",
    *      "released": 1942,
    *      "color": true,
    *      "Actors": [
    *         "Humph Boke",
    *         "Inge ZZ"
    *      ]
    *   }
    *]
    

Go复合数据类型学习总结相关推荐

  1. 《Go语言圣经》学习笔记 第四章 复合数据类型

    <Go语言圣经>学习笔记 第四章 复合数据类型 目录 数组 Slice Map 结构体 JSON 文本和HTML模板 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. ...

  2. 学习C++复合数据类型

    复合数据类型 String 类型 char str[20]; //strlen(str)的长度不一定是20 cin.getline(str,20); //读入一行输入(cin是iostream类的一个 ...

  3. 五、Go语言复合数据类型(下)

    @Author:Runsen 复合数据类型主要包含Go中的一些复杂类型,主要有指针类型,数组类型,切片类型,结构体类型,Map类型和Channel类型 下面,我们继续学习结构体类型,Map类型和Cha ...

  4. 春晚黑科技全盘点:刘德华、周杰伦到底来没来?Ubuntu linux c复合数据类型--结构体

    本文转载自IT之家,刘德华.周杰伦到底有没有来春晚? 很多看了 2021 年央视春晚的人会对这个问题感兴趣--其实,周杰伦.刘德华是通过 AR.云技术 "出现"在现场的. 央视春晚 ...

  5. golang json转结构体中嵌套多个数组_ElasticSearch第六篇:复合数据类型-数组,对象...

    在ElasticSearch中,使用JSON结构来存储数据,一个Key/Value对是JSON的一个字段,而Value可以是基础数据类型,也可以是数组,文档(也叫对象),或文档数组,因此,每个JSON ...

  6. 【oracle】复合数据类型

    [oracle]复合数据类型 1123-02 更新 复合数据类型 复合数据类型举例 1.record set serveroutput on; /* 复合数据类型--记录:for循环中 给 记录类型变 ...

  7. PL/SQL-2 复合数据类型

    -------------------------------------------------------------------------- ************************* ...

  8. PL/SQL复合数据类型

    --一.PL/SQL复合数据类型 --(一).PL/SQL记录 --1.定义PL/SQL记录 --(1).定义PL/SQL记录 --Grammar TYPE type_name IS RECORD(f ...

  9. java中的复合数据类型是什么_【填空题】类是Java中的一种重要的复合数据类型,是组成Java程序的基本要素。一个类的实现包括两部分:____和_____....

    [填空题]类是Java中的一种重要的复合数据类型,是组成Java程序的基本要素.一个类的实现包括两部分:____和_____. 更多相关问题 [名词解释] 观叶树木 [单选] 开花时有浓郁香气的树种是 ...

最新文章

  1. Python使用matplotlib可视化小提琴图、seaborn中的violinplot函数可视化多分类变量的小提琴图(Violin Plot)
  2. ERR_CONTENT_LENGTH_MISMATCH
  3. java 正则匹配 sql星号,18. 正则表达式:开头、结尾、任意一个字符、星号和加号匹配...
  4. Python IDLE 如何清屏
  5. linux驱动之I2C
  6. VS2010 + OpenCV 2.4.1 环境配置
  7. 错误./hello: error while loading shared libraries: libQtGui.so.4: cannot open shared object file:
  8. 【Elasticsearch】es 定期删除 已经删除的数据 物理删除 不是等待段合并
  9. 4.13_chain_of_responsibility_行为型模式:责任链模式
  10. caffe利用shell创建train.txt和val.txt做数据输入
  11. 分享 那些经典电影的经典台词
  12. 洛谷P3239 [HNOI2015]亚瑟王
  13. spaCy 2.1 中文NLP模型
  14. pytorch(7)——二十二种transforms数据预处理方法
  15. dymola学习笔记第三天——胡言乱语篇
  16. minSdk(API 29) deviceSdk(API 127)
  17. win7下ie6兼容测试之Windows7(win7)下 XP Mode 下载、安装、设置完全图解
  18. 网页代码基本结构以及html标签的使用
  19. java分页查询_java实现分页查询
  20. 微信小程序如何打开网页

热门文章

  1. 虚拟机服务器桥接网络配置,虚拟机Vmware下CentOS6.5配置Bridged桥接方式上网及远程登录...
  2. 育儿品牌“亲宝宝”获数亿元C轮融资,好未来领投,顺为、复星跟投
  3. 造轮子之Vue实现原理,几十行代码实现Vue
  4. KEIL 创建静态链接库+ 调用自己创建的静态链接库
  5. Python学习13-15.1-15.12 保持时间、计划任务和启动程序
  6. std::map emplace和insert使用
  7. 漫步STL-map AND set
  8. windows不是正版电脑壁纸变黑色
  9. uboot 引导wince NK.nb0
  10. 数迹智能 VisionChina(上海)2020 展精彩回顾