基本语法对比
声明 | 值长什么样? | |
---|---|---|
整型/浮点型/复数/字符串/字符 | var a int |
25/26.3/10 + 2*i/"good"/'g' |
指针 | var prt *int |
0**<font style="color:rgb(51, 51, 51);">xc0000a0063</font>** 一般用*prt 或者 prt/ new(int) |
数组 | **<font style="color:rgb(51, 51, 51);">var</font>** a [<font style="color:rgb(0, 128, 128);">5</font>]**<font style="color:rgb(51, 51, 51);">int</font>** |
[5]int{1,2,3,4,5} |
切片 | var a []string |
[]int{1,2,3,4,5,6} |
集合 | var a [string] int |
map[string]int{"Tom":1, "Bob":2} (集合必须写key-value,不能像结构那样省略,因为集合是无序地) |
结构体 | type person struct{....} + var man_1 person |
person{"Bob": 24, "Justin":23 } / 可以不写key,如 person{24, 23} ,但要求 全部、按序、不能混地初始化 |
思想
要用模块化的思想,而非分支,因为分支实在太多
- 仅声明
var x type
- 初始化
- 左边
var x =
/x :=
- 右边——数据
- 数据长什么样必须清楚,尤其是数组、切片、集合、结构体,上图已展示
- 特殊情况需要
var a type = ...
什么特殊情况?——type是自定义的,相对比较复杂的- 结构体不需要,因为值里带了结构体类型别名
- 函数类型变量推荐写(好像也没那么需要)
- 自定义类型,由于实现方法的类型,必须经过type定义,故在方法里最常用
<font style="color:#E8323C;">type Myint int</font>
<font style="color:#E8323C;">var x Myint = 10</font>
- 左边
- 类型
- 仅声明,类型必须有
- 若使用var关键字
var x int/float/string/complex64
右边类型必须要- 对于指针、数组、切片、集合、结构体 。。。。,尾巴可省略——
var x
- 注意,不像python用方括号和花括号区分不同组合类型,而通过开头
- 数组
[...]int {1,2,3,4,5}
- 切片
[]int{1,2,3,4,5}
- 集合
map[string]int{...:..., ...:,... }
- 结构体
person{...:..., ...:...}
(person是之前已经定义好的类型)
- 数组
数组 | 切片 | 集合 | 结构体 | |
---|---|---|---|---|
范围 | 全局var a / 局部 a := |
范围和左侧相同,这里只提一个结构体指针注意一下 1. 全局变量 var man_1 = ... (如果左边写变量类型,一般变量写person,结构体型指针写*person)2. 局部变量 man_1 := ... |
||
类型处理 1. 结构体类型长这样: struct{...} 和int/float/... 同地位 如struct{Name string; Age int} 2. 直接用——匿名结构体 1. 和声明变量一起 var user struct{Name string; Age int} 2. 和初始化一起 3. 先定义结构类型,之后再用 |
||||
声明 | 1. 由于数组是值类型,声明与初始化为零值作用相同 1. 声明 **<font style="color:rgb(51, 51, 51);">var</font>** a [len]**<font style="color:rgb(51, 51, 51);">type</font>** 2. 初始化为零值: **<font style="color:rgb(51, 51, 51);">var a = [5]type{}</font>** / a := [len]type{} |
var s_1 []type 仅声明,之后可以整体赋值,但是不可单独赋值并不推荐,因为切片是引用类型,仅仅只是声明无初始化为零值,系统并未分配底层数组 |
var a [string]int 仅仅声明,并未初始化,不可调用,不推荐 |
仅变量声明 var man_1 person / var man_1 *person 1. 结构就一值类型,和int、float、string….同地位, 仅声明=初始化为零值 (结构体指针不同,必须初始化为零值或者给予地址后才可以用) 2. 初始化成什么变量? 1. 一般变量 右边—— person{} 2. 指针变量 右边——&person{} /右边——new(perosn) |
初始化为零值 | 等式右边 1. 设定len和cap: make ([]type, len, cap) 2. 不设定 : []type{} |
等式右边: 1. **<font style="color:rgb(51, 51, 51);">make</font>**(**<font style="color:rgb(51, 51, 51);">map</font>**[string]int, 5, 7) 2. <font style="color:#c7773e;">map</font>[<font style="color:#c7773e;">string</font>]<font style="color:#c7773e;">int</font>{} |
||
初始化 | 1. {}怎么塞? 1. 一维数组 1. 不完全赋值 [5]int{1, 2, 3} /[5]string{3: "hello world", 4: "tom"} 2. 完全赋值 [5]int{1, 2, 3, 4, 5} /[...]int{1, 2, 3, 4, 5, 6} 2. 多维数组 1. [2][3]int{{1, 2, 3}, {7, 8, 9}} 2. 可省略第一个 [...][3]int{{1, 2, 3}, {7, 8, 9}} 2. 用下标,挨个赋值 arr [i] = 3. 组合 **类型——注意一下struct类型 ** |
1. 直接塞[]type {...., ....} 2. 截取别的数组 other_s [a:b:c] (a,b,c皆可省略) **重点知道cap怎么计算** |
直接赋值 挨个赋值 map_1[key] = value |
赋值 1. 塞花括号:用键值对/ 只给value 2. 挨个赋值: <font style="color:rgb(51, 51, 51);">man_1.name = ... </font> |
调用 | 下标 a[3] |
下标s_1[3] |
map_1[key] = value |
<font style="color:rgb(51, 51, 51);">man_1.name = ... </font> |
多维 | 如果是多维数组,则类型改成 [len_1][len_2]type 如果要赋值: [len_1][len_2]type{{1, 1}, {2, 2}, {3, 3}} |
如果是二维度切片,目前不知道make怎么弄,但直接赋值可,且二维切片可不同维度不同维数 |
组合
???
初始化
值类型声明,即初始化为零值,但引用类型声明后,初始化为nil,必须实例化/初始化为零值后才可调用
关键字
type
类型定义
<font style="color:rgb(18, 18, 18);">type typeName baseType</font>
- typeName 为定义的类型名称
- baseType 依赖的类型,Go 语言中所有的数据类型都可以,还有待会要讲的结构体 struct
:::info 应用
:::
给类型定义类型别名,什么情况会需要呢?
- 自定义类型(复合)
- 结构体
- 函数类型
type 类型别名 函数类型
比如type Func_type func(a, b int)
- 结构体
- 一般变量别名
type MyInt **<font style="color:rgb(51, 51, 51);">int</font>**_<font style="color:rgb(153, 153, 136);">//将MyInt定义为int类型</font>_
类型别名
- 语法结构:
<font style="color:rgb(0, 134, 179);">type</font> TypeAlias = Type
- 类型别名是Go1.9版本添加的新功能。
- 类型别名规定:TypeAlias只是Type的别名,本质上TypeAlias与Type是同一个类型。就像一个孩子小时候有小名、乳名,上学后用学名,英语老师又会给他起英文名,但这些名字都指的是他本人。
- 实例:
我们之前见过的rune和byte就是类型别名,他们的定义如下:<font style="color:rgb(0, 134, 179);">type</font> byte = uint8
<font style="color:rgb(0, 134, 179);">type</font> rune = int32
区别
上面其实已经说明了,主要表现于类型转化上
- 类型定义,是创建一个全新类型,即使
type str_type string; var str_1 str_type = "good"
- 类型别名,不创建新的类型,只是多一个指针,仍然指向原类型
知乎解释:
创建变量的函数
make
a := make([]string, len, cap)
b := make([string]int, len)//len=cap
c := make(?)//
:::info 作用
:::
make也是用于内存分配的,区别于new,它只用于slice、map以及chan的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。:::info
make函数的函数签名如下::::
**<font style="color:rgb(51, 51, 51);">func</font>** **<font style="color:rgb(51, 51, 51);">make</font>**(**<font style="color:rgb(51, 51, 51);">t</font>** **<font style="color:rgb(51, 51, 51);">Type</font>**, **<font style="color:rgb(51, 51, 51);">size</font>** ...IntegerType) **<font style="color:rgb(51, 51, 51);">Type</font>**
new
为创建指针而生
函数签名:func **<font style="color:rgb(51, 51, 51);">new</font>**(Type) *Type
其中:
- 接受:一个类型Type
- 返回:这个类型的指针 *Type
作用:
new函数不太常用,使用new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值。(特别注意:这里和默认初始化的nil,也就是空指针,还是有区别)实例:
func main() {
a := new(int)
b := new(bool)
fmt.Printf("%T\n", a) // *int
fmt.Printf("%T\n", b) // *bool
fmt.Println(*a) // 0
fmt.Println(*b) // false
}
由于用new函数创建指针,其值为对应其类型的零值,故可直接赋值
func main() {
var a *int
a = new(int)
*a = 10//这就行了
fmt.Println(*a)
}
其他
成员运算符—点号.
- 访问结构体成员,
结构体.结构体成员
=该结构体成员的值 - 方法:
- 基本运用
符合接收者类型的变量.方法(...参数)
- 方法值,隐藏方法和接收者,
pFunc := var_receiver.a
➡pFunc(...参数)
- 方法表达式,隐藏方法,保留接收者,
pFunc := (receiver).method
➡pFunc(...var_receiver, ...参数)
receiver是接收者类型,var_receiver是符合接收者类型的变量
- 基本运用
- 接口
接口变量.方法
- 某包的函数/方法调用
包.函数/方法
比如fmt.Printf(...)