GO笔记之基本类型和语法

GO基本类型枚举

类型 长度 默认值 说明
bool 1 false 布尔类型
byte 1 0 uint8
rune 1 0 int32的别名,Unicode Code Point。返回utf-8字符串的字符长度而不是内存长度
int, uint 4或者8 0 32位机器上就是32位,64位机器上就是64位
int8, uint8 1 0 -128 ~ 127, 0 ~ 255
int16, uint16 2 0 -32768 ~ 32767, 0 ~ 65535
int32, uint32 4 0 -2147483648~ 2147483647, 0 ~ 4294967295
int64, uint64 8 0 -9223372036854775808~9223372036854775807,0~18446744073709551615
float32 4 0.0 1.4e-45~3.4e38,小数点后6位精度
float64 8 0.0 4.9e-324~1.8e308,小数点后15位精度
complex64 8 0+0i 32 位实数和虚数
complex128 16 0+0i 64 位实数和虚数
uintptr 4或8 0 足以存储指针的 uint32 或 uint64 整数
array 数组,值类型
struct 结构体,值类型
string "" 字符串类型
slice nil 切片,底层是数组。引用类型
map nil 引用类型
channel nil 通道,引用类型
interface nil 接口
function nil 函数

go 中类型之间必须显示转换。

可以将类型分为命名未命名两类。命名类型包括 bool、int、string 等,⽽而 array、slice、map 等和具体元素类型、⻓长度等有关,属于未命名类型。

具有相同声明的未命名类型被视为同一类型。如:

  • 具有相同基类型的指针。
  • 具有相同元素类型和⻓长度的数组。
  • 具有相同元素类型的slice
  • 具有相同键值的map
  • 具有相同元素类型和传送⽅方向的 channel
  • 具有相同字段序列 (字段名、类型、标签、顺序) 的匿名 struct
  • 签名相同 (参数和返回值,不包括参数名称) 的 func
  • ⽅方法集相同 (⽅方法名、⽅方法签名相同,和次序⽆无关) 的 interface。

new和make

内置函数 new 计算类型⼤大⼩小,为其分配零值内存,返回指针。⽽而 make 会被编译器翻译 成具体的创建函数,由其分配内存和初始化成员结构,返回对象⽽而⾮非指针。引用类型需要由 make 创建。

字符串

字符串是不可变值类型,内部⽤用指针指向 UTF-8 字节数组。 默认值是空字符串 ""。

  • ⽤用索引号访问某字节,如 s[i]。
  • 不能⽤用序号获取字节元素指针,&s[i] ⾮非法。
  • 不可变类型,⽆无法修改字节数组。
  • 字节数组尾部不包含 NULL。
  • 使⽤用索引号访问字符 (byte)。
1
2
3
4
 s := "abc"
println(s[0] == '\x61', s[1] == 'b', s[2] == 0x63)
// 输出
true true true
  • 使⽤用 "`" 定义不做转义处理的原始字符串,⽀持跨⾏。
  • []byte 和 []rune 在字符处理上的差异:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {
    s := "abc你好"
    // byte
	for i := 0; i < len(s); i++ {
		fmt.Printf("%c,", s[i])
	}
    fmt.Println()
    // rune
	for _, r := range s {
		fmt.Printf("%c,", r)
	}
}

输出:

1
2
a,b,c,ä,½, ,å,¥,½,
a,b,c,你,好,

指针

⽀支持指针类型 *T,指针的指针 **T。不能对指针做算术运算。

  • 默认值nil,用“.”访问目标成员。
  • 操作符 "&" 取变量地址,"*" 透过指针访问目标对象。
  • 可以在 unsafe.Pointer 和任意类型指针间进⾏行转换。指针类型之间不可以强制转换为此引入unsafe特殊场景下使用它可以打破go的类型和内存安全机制,但是用着不安全。所以有了unsafe.Pointer,它表示任意类型且可寻址的指针值,可以在不同的指针类型之间进行转换。
    • 任何类型的指针值都可以转换为 Pointer
    • Pointer 可以转换为任何类型的指针值
    • uintptr 可以转换为 Pointeruintptr是 Go 的内置类型。返回无符号整数,可存储一个完整的地址,用于指针运算。也就是说将指针转换为uintptr可以变相实现指针运算。
    • Pointer 可以转换为 uintptr
    • uintptr 被GC当作普通整数,不能阻止所"引用"的对象被收回。
    • 指正构成的循环引用加上runtime.SetFinalizer会导致内存泄露。 引用 https://segmentfault.com/a/1190000017389782 中的内容说明:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
type Num struct{
    i string
    j int64
}

func main(){
    n := Num{i: "EDDYCJY", j: 1}
    nPointer := unsafe.Pointer(&n)

    niPointer := (*string)(unsafe.Pointer(nPointer))
    *niPointer = "煎鱼"

    njPointer := (*int64)(unsafe.Pointer(uintptr(nPointer) + unsafe.Offsetof(n.j)))
    *njPointer = 2

    fmt.Printf("n.i: %s, n.j: %d", n.i, n.j)
}

在剖析这段代码做了什么事之前,我们需要了解结构体的一些基本概念:

  • 结构体的成员变量在内存存储上是一段连续的内存
  • 结构体的初始地址就是第一个成员变量的内存地址
  • 基于结构体的成员地址去计算偏移量。就能够得出其他成员变量的内存地址 再回来看看上述代码,得出执行流程:
  • 修改 n.i 值:i 为第一个成员变量。因此不需要进行偏移量计算,直接取出指针后转换为 Pointer,再强制转换为字符串类型的指针值即可。
  • 修改 n.j 值:j 为第二个成员变量。需要进行偏移量计算,才可以对其内存地址进行修改。在进行了偏移运算后,当前地址已经指向第二个成员变量。接着重复转换赋值即可。
  • unsafe.Offsetof:返回成员变量 x 在结构体当中的偏移量。更具体的讲,就是返回结构体初始位置到 x 之间的字节数。需要注意的是入参 ArbitraryType 表示任意类型,并非定义的 int。它实际作用是一个占位符。

表达式

保留字:

break case chan const
continue default func defer
go else goto fallthrough
if for import interface
map package range return
select struct switch type
var

所有符号:

+ & += &= && == !=
- | -= |= || < <=
* ^ *= ^= <- > >=
/ << /= <<= ++ = :=
% >> %= >>= -- ! ...
&^ &^=

运算符优先级

从高到低:

* / & << >> & &^
+ - | ^
== != < <= < >=
<- && ||

语法相关

  • range 返回的第一个值是key,第二个是value。当只写一个接收变量时获得key
  • range 取到的值是一个复制,对其修改不会影响原有对象。
  • mapchannel 是指针包装,slice 底层是数组,被定义为一个struct
  • switch 自动break,使用fallthrough关键字可以继续下一分支,但是不再判断条件。
  • 为加强代码可读性不太建议使用goto语法。
  • 函数不支持嵌套,重载,默认参数。
  • 对于数组而言,内置函数 len 和 cap 都返回数组⻓长度 (元素数量)。
updatedupdated2020-05-262020-05-26
加载评论