Go 入门 - Go中的复杂类型
主要内容来自中文版的官方教程Go语言之旅
目的为总结要点
指针
Go 拥有指针。指针保存了值的内存地址。
类型 *T
是指向 T
类型值的指针。其零值为 nil
。
var p *int
&
操作符会生成一个指向其操作数的指针。
i := 42
p = &i
*
操作符表示指针指向的底层值。
fmt.Println(*p) // 通过指针 p 读取 i
*p = 21 // 通过指针 p 设置 i
这也就是通常所说的“间接引用”或“重定向”。
与 C 不同,Go 没有指针运算。
package main
import "fmt"
func main() {
i, j := 42, 2701
p := &i // point to i
fmt.Println(*p) // read i through the pointer
fmt.Println(p)
*p = 21 // set i through the pointer
fmt.Println(i) // see the new value of i
p = &j // point to j
*p = *p / 37 // divide j through the pointer
fmt.Println(j) // see the new value of j
}
// output
// 42
// 0xc420084010
// 21
// 73
结构体
结构体是一些变量的集合,可以用以下方式创建一个结构体。修改结构体可以采用.
符号,指向结构体的指针也可以用同样的方法来访问。
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1,2}
fmt.Println(v)
v.X = 4
fmt.Println(v)
p := &v
p.X = 8
fmt.Println(v)
}
//output {1 2} {4 2} {8 2}
结构体与结构体的指针都可以用以下的方法初始化
package main
import "fmt"
type Vertex struct {
X, Y int
}
var (
v1 = Vertex{1, 2} // has type Vertex
v2 = Vertex{X: 1} // Y:0 is implicit
v3 = Vertex{} // X:0 and Y:0
p = &Vertex{1, 2} // has type *Vertex
)
func main() {
fmt.Println(v1, p, v2, v3)
}
数组与切片
数组的声明也是从做到右的,以var
开头的或者短声明
var a [2] string
var a [10] int
primes := [6]{2, 3, 5, 7}
切片
类型[]T
表示一个元素类型为T
的切片。切片通过两个下标界定a[low:high]
,这种切片会选择一个半开区间,包含第一个元素但是排除最后一个元素。切片下界的默认值是0,上界的默认值是该切片的长度。这里注意,如果制定了长度,那么得到的就是数组,在Go中数组是作为值传递的,会耗费很多的内存。
package main
import "fmt"
func main() {
primes := [6]int{2, 3, 5, 7, 11, 13} // 这是一个数组
var s []int = primes[1:4] // 这是在声明一个切片
fmt.Println(s)
names := [4]string{
"John","Paul","George","Ringo",
} // 这是一个数组
fmt.Println(names)
a := names[0:2] // 这也是一个切片
b := names[1:3] // 这也是一个切片
fmt.Println(a, b) // output [John Pul] [Paul George]
b[0] = "XXX"
fmt.Println(a, b) // output [John XXX] [XXX George]
fmt.Println(names) // output [John XXX George Ringo]
}
一个切片本身是底层数组的引用,多个切片可以共享一个底层数组,在一个切片上的修改可以影响到底层数组,进而影响到所有切片
切片拥有 长度 和 容量。对于切片s
,长度是切片的长度,可以用len(s)
获得,容量是从切片的第一个元素开始数一直到底层数组的长度,可以用cap(s)
获得。
从底层数组的视角来看,切片中有意义的量只有三个,分别是起始位置,长度和容量。其中长度和容量是反映在切片自身重点,起始位置是用于锚定切片在底层数组中的位置。一旦切片建立,那么底层数组在起始位置之前的部分就会被扔掉。
在做切片的时候,其实s[low: high]
中的low
就选择了在当前的底层数组中的起始位置,high
选择了终止位置,进而定义了长度high-low
。在简历切片之后,底层数组精简原底层数组中low
到末尾的部分。
nil
切片是切片长度和容量都为零,且没有底层数组的切片,例如它可以这样声明var s []int
。其实在这个意义上,数组自身就是长度和容量相等的切片。
切片可以包含任何类型,甚至其他的切片(多维数组)
board := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}
用range
遍历切片
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
for _, value := range pow {
fmt.Printf("%d\n", value)
}
for value, _ := range pow {
fmt.Printf("%d\n", value)
}
}
映射
映射将key映射到value。用make
函数可以创建给定类型的映射,并将其初始化备用。
映射的零值为nil
,需要注意的是nil
既没有键,也不能添加键
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex
func main() {
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])
}
映射的文法和结构体类似,但是一定要有键名
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967,
},
"Google": Vertex{
37.42202, -122.08408,
},
}
func main() {
fmt.Println(m)
}
映射可以用下标访问或修改元素
用delete
函数删除元素
用双赋值可以检测某个键的是否存在
package main
import "fmt"
func main() {
m := make(map[string]int)
m["Answer"] = 42
fmt.Println("The value:", m["Answer"])
m["Answer"] = 48
fmt.Println("The value:", m["Answer"])
delete(m, "Answer")
fmt.Println("The value:", m["Answer"])
v, ok := m["Answer"]
fmt.Println("The value:", v, "Present?", ok) // ok 是是否存在的boolean值
}
函数值
函数本身也可以作为值,称为函数值,可以作为函数的参数或者返回值
package main
import (
"fmt"
"math"
)
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}
Go函数可以使一个闭包。闭包是一个函数值,它引用了函数体之内的变量。该函数可以访问并赋予其引用的变量的值。例如下面的例子中adder
函数返回值为一个闭包。每个闭包都被绑定在各自的sum
变量上。
package main
import "fmt"
func adder() func(int) int {
sum := 0 //这是闭包的函数体之外的变量,它也被绑定在闭包内了
return func(x int) int { //这是闭包
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
make函数
用make函数创建切片(动态数组),有两种用法
a := make([]int, 5) // 长度为5,容量默认为5
b := make([]int, 0, 5) // 长度为0, 容量为5
func make([]T, len, cap) []T
用make
函数可以创建给定类型的映射,并将其初始化备用
Go 入门 - Go中的复杂类型的更多相关文章
- javaScript中Number数字类型方法入门
前言 Number和Math都属于JavaScript中的内置对象,Number数字类型作为基础数据类型,我们在开发过程中会经常用到,包括数字精度的格式化,还有字符串转换成数字等操作. Number数 ...
- Swift入门(四)——可选类型(Optionals)与断言(Assert)
可选类型是什么? 首先看一个问题,Swift中String类型的变量有一个叫做toInt的方法,能够把String类型变量转换为Int类型变量. var stringValue = "5&q ...
- 一步一步带你入门MySQL中的索引和锁 (转)
出处: 一步一步带你入门MySQL中的索引和锁 索引 索引常见的几种类型 索引常见的类型有哈希索引,有序数组索引,二叉树索引,跳表等等.本文主要探讨 MySQL 的默认存储引擎 InnoDB 的索引结 ...
- Entity Framework 教程——Entity Framework中的实体类型
Entity Framework中的实体类型 : 在之前的章节中我们介绍过从已有的数据库中创建EDM,它包含数据库中每个表所对应的实体.在EF 5.0/6.0中,存在POCO 实体和动态代理实体两种. ...
- Python中内置数据类型list,tuple,dict,set的区别和用法
Python中内置数据类型list,tuple,dict,set的区别和用法 Python语言简洁明了,可以用较少的代码实现同样的功能.这其中Python的四个内置数据类型功不可没,他们即是list, ...
- 向mysql中插入Date类型的数据
先看数据库表的定义 date字段为sql.date类型.我要向其中插入指定的日期和当前日期. 一.插入当前日期 思路:先获取当前系统,在将当前系统时间转换成sql类型的时间,然后插入数据库.代码如下 ...
- 在文件夹中 的指定类型文件中 查找字符串(CodeBlocks+GCC编译,控制台程序,仅能在Windows上运行)
说明: 程序使用 io.h 中的 _findfirst 和 _findnext 函数遍历文件夹,故而程序只能在 Windows 下使用. 程序遍历当前文件夹,对其中的文件夹执行递归遍历.同时检查遍历到 ...
- Python 中的枚举类型~转
Python 中的枚举类型 摘要: 枚举类型可以看作是一种标签或是一系列常量的集合,通常用于表示某些特定的有限集合,例如星期.月份.状态等. 枚举类型可以看作是一种标签或是一系列常量的集合,通常用于表 ...
- UNIX中的文件类型
Unix的文件类型信息包含在stat结构的st_mode成员中可以用宏确定文件类型: 普通文件(S_ISREG()):包含某种形式数据的常用文件类型 目录文件(S_ISDIR()):这种文件包含其他文 ...
随机推荐
- sqoop部署与使用
sqoop安装 1.下载并解压 scp sqoop-1.4.6.bin__hadoop-2.0.4-alpha.tar.gz mini1:/root/apps/ tar -zxvf sqoop-1.4 ...
- Oracle练习详解
--1.查询emp表,显示薪水大于2000,且工作类别是MANAGER的雇员信息 select * from emp where sal > 2000and job = 'MANAGER'; - ...
- postgres if ,when及判断表是否存在的sql编写
判断表是否存在方法1: SELECT THEN END FROM ( select count(*) as cc from pg_class where relname = 'wo' --wo is ...
- Windows Server 2008 安装wampserver失败的总结
1.最好选择2.4以下版本. 2.如果报确实MSVCR100.dll的错误,需要下载运行环境包(参考博客)
- BIND简易教程(0):在Ubuntu下源码安装BIND(其实跟前面的教程没太大关系)
之前介绍过BIND的基本使用啦.关于BIND的入门级使用方法见:http://www.cnblogs.com/anpengapple/p/5877661.html简易教程系列,本篇只讲BIND安装. ...
- Hibernate之CRUD实践
Hibernate作为一个高度封装的持久层框架,曾经是非常牛逼的,现在虽然应用不是特别广,比如我前公司主要是做OA的,应用的框架就是Spring+SpringMVC+Hibernate. Hibern ...
- 用@ExceptionHandler 来进行异常处理
有时候我们想统一处理一个Controller中抛出的异常怎么搞呢? 直接在Controller里面加上用@ExceptionHandler标注一个处理异常的方法像下面这样子 @ExceptionHan ...
- 【洛谷P1982】小朋友的数字
小朋友的数字 题目链接 题目翻译: 每个小朋友有一个数字,构成一个数字序列a1,a2…an 我们定义“特征值”fi为a1~ai中的最大连续子段和 再定义“分数”si为1~i-1中最大的(sj+fj), ...
- Finder 的分栏显示模式宽度调整
Mac系统下设置 Finder 分栏默认宽度的方法 苹果电脑 Mac OS X 系统中最重要的功能:Finder 有四种显示模式:图标.列表.分栏.Cover Flow,很多 Mac “老手” ...
- vue 方法相互调用注意事项与详解
vue在同一个组件内: methods中的一个方法调用methods中的另外一个方法: 可以直接这样调用:this.$options.methods.test(); this.$options.met ...