Go语言学习笔记(4)复合类型

 

Go语言的复合类型,包括数组、切片和映射等。

值、指针和引用类型

通常情况下Go语言中的变量持有相应的值。也就是说,我们可以将一个变量想象成它所持有的值来使用。其中有些例外,通道、函数、方法、映射、切片是 引用变量,它们持有的都是引用,也即保存指针的变量。值在传递给函数或者方法的时候会被复制一次,对于布尔类型和数值类型来说这非常廉价,但是对于大型变 量代价却非常大。而且复制传参的方式,修改值只是修改了副本,这能保证原始变量不被修改,但也一定程度上增加了修改原始值的麻烦。幸好在Go语言中有指 针,使用指针时,我们每次传递给函数或者方法的只是变量的内存地址,这是非常廉价的。而且一个被指针指向的变量可以通过该指针来修改,这就很方便的在函数 或者防止中通过指针修改原始变量。Go语言中的指针操作符也是使用&和*操作符,其中&用于取地址,*用于解引用,也就是获取指针指向的值。

使用VIM创建源文件pointer.go,输入以下源文件:

package main

import (

"fmt"

)

func swap1(x, y, p *int) {

if *x > *y {

*x, *y = *y, *x

}

*p = *x * *y

}

func swap2(x, y int) (int, int, int) {

if x > y {

x, y = y, x

}

return x, y, x * y

}

func main() {

i := 9

j := 5

product := 0

swap1(&i, &j, &product)

fmt.Println(i, j, product)

a := 64

b := 23

a, b, p := swap2(a, b)

fmt.Println(a, b, p)

}

以上源码中,我们首先创建了swap1函数,其通过指针原地的交换值,同时swap2函数通过复制的方式交换了变量的值。

运行结果如下:

$ go run pointer.go

5 9 45

23 64 1472

三. 数组和切片

1. 数组

Go语言的数组是一个定长的序列,其中的元素类型相同。多维数组可以简单地使用自身为数组的元素来创建。数组的元素使用操作符号[ ]来索引,索引从0开始,到len(array)-1结束。数组使用以下语法创建:

  • [length]Type
  • [N]Type{value1, value2, ..., valueN}
  • [...]Type{value1, value2, ..., valueN}

如果使用了...(省略符)操作符,Go语言会为我们自动计算数组的长度。在任何情况下,一个数组的长度都是固定的并且不可修改。数组的长度可以使用len()函数获得。由于数组的长度是固定的,因此数组的长度和容量都是一样的,因此对于数组而言cap()和len()函数返回值都是一样的。数组也可以使用和切片一样的语法进行切片,只是其结果为一个切片,而非数组。同样的,数组也可以使用range进行索引访问。

2. 切片

一般而言,Go语言的切片比数组更加灵活,强大而且方便。数组是按值传递的(即是传递的副本),而切片是引用类型,传递切片的成本非常小,而且是定长的。而且数组是定长的,而切片可以调整长度。创建切片的语法如下:

  • make([ ]Type, length, capacity)
  • make([ ]Type, length)
  • [ ]Type{}
  • [ ]Type{value1, value2, ..., valueN}

内置函数make()用于创建切片、映射和通道。当用于创建一个切片时,它会创建一个隐藏的初始化为零值的数组,然后返回一个引用该隐藏数组的切片。该隐藏的数组与Go语言中的所有数组一样,都是固定长度,如果使用第一种语法创建,那么其长度为切片的容量capacity;如果是第二种语法,那么其长度记为切片的长度length。一个切片的容量即为隐藏数组的长度,而其长度则为不超过该容量的任意值。另外可以通过内置的函数append()来增加切片的容量。切片可以支持以下操作:

我们练习下,使用VIM创建源文件slice_array.go,输入以下代码:

package main

import (

"fmt"

)

func main() {

a := [...]int{1, 2, 3, 4, 5, 6, 7}

fmt.Printf("len and cap of array %v is: %d and %d\n", a, len(a), cap(a))

fmt.Printf("item in array: %v is:", a)

for _, value := range a {

fmt.Printf("% d", value)

}

fmt.Println()

s1 := a[3:6]

fmt.Printf("len and cap of slice: %v is: %d and %d\n", s1, len(s1), cap(s1))

fmt.Printf("item in slice: %v is:", s1)

for _, value := range s1 {

fmt.Printf("% d", value)

}

fmt.Println()

s1[0] = 456

fmt.Printf("item in array changed after changing slice: %v is:", s1)

for _, value := range a {

fmt.Printf("% d", value)

}

fmt.Println()

s2 := make([]int, 10, 20)

s2[4] = 5

fmt.Printf("len and cap of slice: %v is: %d and %d\n", s2, len(s2), cap(s2))

fmt.Printf("item in slice %v is:", s2)

for _, value := range s2 {

fmt.Printf("% d", value)

}

fmt.Println()

}

以上代码中,我们首先创建了一个数组,数组的长度是由Go语言自动计算出的(省略号语法),然后通过切片操作从数组a中创建了切片s1,接着我们修改了该切片的第一个位置的数值,然后发现数组a中的值也发生了变化。最后我们通过make()函数创建了一个切片,该切片的长度和容量分别为10和20,还可以发现Go语言将未初始化的项自动赋予零值。运行代码输出如下:

$  go run slice_array.go

len and cap of array [1 2 3 4 5 6 7] is: 7 and 7

item in array: [1 2 3 4 5 6 7] is: 1 2 3 4 5 6 7

len and cap of slice: [4 5 6] is: 3 and 4

item in slice: [4 5 6] is: 4 5 6

item in array changed after changing slice: [456 5 6] is: 1 2 3 456 5 6 7

len and cap of slice: [0 0 0 0 5 0 0 0 0 0] is: 10 and 20

item in slice [0 0 0 0 5 0 0 0 0 0] is: 0 0 0 0 5 0 0 0 0 0

四. 映射(map)

Go语言中的映射(map)是一种内置的数据结构,保存键=值对的无序集合,它的容量只受到机器内存的限制,类似于Python中的字典。在一个映射中所有的键都是唯一的而且必须是支持==和!=操作符的类型,大部分Go语言的基本类型都可以作为映射的键,但是切片、不能用于比较的数组、结构体(这些类型的成员或者字段不支持==和!=操作)或者基于这些的自定义类型不能作为键。但是任意类型都可以作为值。映射是引用类型,所以传递非常廉价。

Go语言中的映射可以用以下用法创建:

  • make(map[KeyType]VauleType, initialCapacity)
  • make(map[KeyType]ValueType)
  • map[KeyType]ValueType{ }
  • map[KeyType]ValueType{key1: value1, key2: value2, ..., keyN: valueN}

内置的函数make()可以用来创建切片、映射和channel(通道)。当用make()来创建一个映射时候,实际上是得到一个空映射,如果指定了容量(initialCapacity)就会预先申请足够的内存,并随着加入的项越来越多,映射会字段扩容。映射支持以下操作:


语法


含义


m[k] = v


用键k来将值赋值给映射m。如果映射m中的k已存在,则将之前的值舍弃


delete(m, k)


将键k及其相关的值从映射m中删除,如果k不存在则不执行任何操作


v := m[k]


从映射m中取得键k相对应的值并赋值给v。如果k不存在,则将映射类型的0值赋值v


v, found := m[k]


从映射m中取得键k相对应的值并赋值给v, 并将found的值赋值为false。如果k不存在,则found为false


len(m)


返回映射m中的项


k := range m


遍历映射m中的键


k, v := range m


同时遍历映射中的键和值

接下来我们练习下。使用VIM创建源文件map_t.go输入以下代码:

package main

import (

"fmt"

)

func main() {

shiyanlou := make(map[string]string) // 与 map[string]string 相同

shiyanlou["golang"] = "docker"

shiyanlou["python"] = "flask web framework"

shiyanlou["linux"] = "sys administrator"

fmt.Print("Traverse all keys: ")

for key := range shiyanlou {    // 遍历了映射的所有键

fmt.Printf("% s ", key)

}

fmt.Println()

delete(shiyanlou, "linux")  // 从映射中删除键"linux"及其值

shiyanlou["golang"] = "beego web framework" // 更新键“golang"的值

v, found := shiyanlou["linux"]

fmt.Printf("Found key \"linux\" Yes or False: %t, value of key \"linux\": \"%s\"", found, v)

fmt.Println()

fmt.Println("Traverse all keys/values after changed:")

for k, v := range shiyanlou {   //遍历了映射的所有键/值对

fmt.Printf("\"%s\": \"%s\"\n", k, v)

}

}

以上代码中,我们首先创建了一个映射,然后赋值了3个键/值对,然后我们遍历了映射中的所有键,使用delete()函数删除了映射中的一个键,然后再次遍历打印了映射。映射的操作都非常简单,多多练习即可。

运行结果如下:

$ go run map_t.go

Traverse all keys: golang python linux

Found key "linux" Yes or False: false, value of key "linux": ""

Traverse all keys/values after changed:

"golang": "beego web framework"

"python": "flask web framework"

时间: 2024-10-14 15:05:37

Go语言学习笔记(4)复合类型的相关文章

C++学习笔记之四 复合类型1

1.数组 声明格式:float loans[20]; loans的类型不是"数组",而是"float 数组".这强调数组是使用float类型创建的.其中,方括号中的元素个数必须为整型常数或const值,也可以是常量表达式(如8*sizeof(int)),但不能是变量,因为变量的值是在程序运行时设置的. 需要注意的是:C++数组从0开始编号,C++使用带索引的方括号表示法来指定数组元素.例如months[0]是months数组的第一个元素,months[11]是最后一

初步swift语言学习笔记2(可选类型?和隐式可选类型!)

作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/28904115 转载请注明出处 假设认为文章对你有所帮助.请通过留言或关注微信公众帐号fengsh998来支持我,谢谢. 可选类型.隐式可选类型 在swift中.可选类型其根源是一个枚举型.里面有None和Some两种类型.事实上所谓的nil就是Optional.None, 非nil就是Optional.Some, 然后会通过Some(T)包装(wrap)原始值,这

初探swift语言的学习笔记(可选类型?和隐式可选类型!)

可选类型.隐式可选类型 其次swift还引入一个较有趣的初始值设置语法使用"?"操作符及"!"号操作符 如:"var optionalString: String? = "Hello" optionalString == nil var optionalName: String? = "John Appleseed" var greeting = "Hello!" if let name = op

Go语言学习笔记(二) [变量、类型、关键字]

日期:2014年7月19日 1.Go 在语法上有着类 C 的感觉.如果你希望将两个(或更多)语句放在一行书写,它们 必须用分号分隔.一般情况下,你不需要分号. 2.Go 同其他语言不同的地方在于变量的类型在变量名的后面.例如:不是,int a,而是 a int.当定义了一个变量,它默认赋值为其类型的 null 值.这意味着,在 var a int后,a 的 值为 0.而 var s string,意味着 s 被赋值为零长度字符串,也就是 "". 3.Go语言的变量声明和赋值 在Go中使

R语言学习笔记

參考:W.N. Venables, D.M. Smith and the R DCT: Introduction to R -- Notes on R: A Programming Environment for Data Analysis and Graphics,2003. http://bayes.math.montana.edu/Rweb/Rnotes/R.html 前言:关于R 在R的官方教程里是这么给R下注解的:一个数据分析和图形显示的程序设计环境(A system for data

go语言学习笔记

go语言学习笔记 go语言学习笔记(初级) 最近一直在学习go语言,因此打算学习的时候能够记录 一下笔记.我这个人之前是从来没有记录笔记的习惯, 一直以来都是靠强大的记忆力去把一些要点记住. 读书的时候因为一直都是有一个很安静和很专心的环境, 因此很多事情都能记得很清楚,思考的很透彻.但是随着 年纪不断增加,也算是经历了很多的事情,加上工作有时会让人 特别烦闷,很难把心好好静下来去学习,去思考大自然的终极 奥秘,因此需要记录一些东西,这些东西一方面可以作为一种自我激励 的机制,另一方面,也算是自

JavaScript--基于对象的脚本语言学习笔记(一)

1.两种嵌入js的方式 使用javascript前缀构建url:<a href="javascript:alert('运行JavaScript..')">运行js</a> js脚本放在<style></style>之间: <style type="text/javascript"> alert("运行JavaScript..") </script> 2.如果没有声明变量直接使

Go语言学习笔记(四) [array、slices、map]

日期:2014年7月22日 一.array[数组] 1.定义:array 由 [n]<type> 定义,n 标示 array 的长度,而 <type> 标示希望存储的内容的类型. 例如: var arr[10] int arr[0] = 1 arr[1] = 2 数组值类型的:将一个数组赋值给 另一个数组,会复制所有的元素.另外,当向函数内传递一个数组的时候,它将获得一个数组的副本,而不是数组的指针. 2.数组的复合声明.a :=[3]int{1,2,3}或简写为a:=[...]i

R语言学习笔记2——绘图

R语言提供了非常强大的图形绘制功能.下面来看一个例子: > dose <- c(20, 30, 40, 45, 60)> drugA <- c(16, 20, 27, 40, 60)> drugB <- c(15, 18, 25, 31, 40) > plot(dose, drugA, type="b") > plot(dose, drugB, type="b") 该例中,我们引入了R语言中第一个绘图函数plot.pl