Go 的类型

1、枚举

Go 并没有明确意义上的 enum 定义,不过可借助 iota 标识符实现一组自增常量值来实现枚举类型。

const (
	x	= iota   // 0
	y            // 1
	z            // 2
)

const (
	_   = iota               // 0
	KB  = 1 << (10 * iota)   // 1 << (10 * 1)
	MB                       // 1 << (10 * 2)
	GB                       // 1 << (10 * 3)
)

自增作用范围为常量组,可在多常量定义中使用多个 iota,它们各自单独计数,只续确保组中每行常量的列数量相同即可。

const (
	_, _ = iota, iota * 10   // 0, 0 * 10
	a, b                     // 1, 1 * 10
	c, d                     // 2, 2 * 10
)

如中断 iota 自增,须必须显示恢复,且后续自增值按行序递增,而非 C enum 那般按上一取值递增。

const (
	a	= iota    // 0
	b             // 1
	c   = 100     // 100
	d             // 100 (与上一行常量右值表达式相同)
	e   = iota    // 4 (恢复 iota 自增,计数包括 c, d)
	f             // 5
)

不同于变量在运行期分配存储内存(非优化状态),常量通常会被编译器在预处理阶段直接展开,作为指令数据使用。

var x = 0x100
const y  =  0x200

func main()  {
	println(&x, x)
	println(&y, y)   // 错误: cannot take the address of y
}

2、基本类型

在使用浮点数时,需要注意小数位的有效精度。

package main

import "fmt"

func main()  {
	var a float32 = 1.1234567899
	var b float32 = 1.12345678
	var c float32 = 1.123456781

	println(a, b, c)
	println(a == b, a == c)
	fmt.Printf("%v  %v, %v\n", a, b, c)
}

其执行结果为:
在这里插入图片描述
在官方的语言规范中,专门提到两个别名。
byte alias for uint8
rune alias for int32
别名类型无须转化,可直接赋值。

package main

func test(x byte)  {
	println(x)

}

func main()  {
	var a byte  = 0x11
	var b uint8  = a
	var c uint8  = a + b

	test(c)

}

其结果输出为:
34

3、引用类型

所谓引用类型特指 slice、map、channel 这三种预定义类型。
相比数字、数组等类型,引用类型拥有更复杂的存储结构。除分配内存外,它们还须初始化一系列属性,诸如指针、长度,甚至包括哈希分布、数据队列等。
内置函数 new 按指定类型长度分配零值内存,返回指针,并不关心类型内部构造和初始化方式。而引用类型则必须使用 make 函数创建,编译器会将 make 转换为目标类型专用的创建函数(或指令),以确保完成全部内存分配和相关属性初始化。
当然, new 函数也可为引用类型分配内存,但这是不完整创建。以字典(map) 为例,它进分配了字典类型本身(实际就是个指针包装)所需内存,并没有分配键值存储内存,也没有初始化散列桶等内部属性,因此它无法正常工作。

package main

import "fmt"

func main()  {
	p := new(map[string]int)
	m := *p
	m["a"] = 1   // panic: panic: assignment to entry in nil map (运行错误)
	fmt.Println(m)
}

4、类型转换

如果转换的目标是指针、单向通道或没有返回值的函数类型,那么必须使用括号,以避免造成语法分解错误。

package main

func main()  {
	x := 100
	p := *int(&x)  // 错误: cannot convert &x (type *int) to type int
	               //  invalid indirect of int(&x) (type int)

	println(p)

}

正确的做法是用括号,让编译器将 *int 解析为指针类型。

	(*int)(p)           // 如果没有括号   ---->   *(int(p))
	(<-chan int)(c)     //                      <-(chan int(c))
	(func())(x)         //                      func() x
	
	func() int(x)       // 		        ---> 有返回值的函数类型可省略括号,但依然建议使用。
	(func()int)(x)      //                    使用括号后,更易阅读

5、自定义类型

使用关键字type 定义用户自定义类型,包括基于现有基础类型创建,或者是结构体、函数类型等。

package main

import "fmt"

type flags = byte

const (
	read  flags  =  1 << iota
	write
	exec
)

func main()  {
	f := read | exec
	fmt.Printf("%b\n", f)

}

输出:
101
即便指定了基础类型、也只表明它们有相同底层数据结构、两者间不存在任何关系,属完全不同的两种类型。除操作符外,自定义类型不会继承基础类型的其他信息(包括方法)。不能视作别名,不能隐式转换,不能直接用于比较表达式。

package main


func main()  {
	type data int
	var d data  = 10

	var x int  = d  // 错误: cannot use d (type data) as type int in assignment
	println(x)

	println(x == d)  // 错误: invalid operation: x == d (mismatched types int and data)

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值