指针
和c一样,也有指针(用*表示),但是进行了一定的简化
支持指针类型 *T
,指针的指针 **T
,以及包含包名前缀的 *<package>.T
。
- 默认值
nil
,没有NULL
常量。 - 操作符 "&" 取变量地址,"*" 透过指针访问目标对象。(跟C一样)
- 不支持指针运算(不能p++,p--),不支持 "->" 运算符
- 直接用 "." 访问目标成员(相较C简化了使用,不再需要将指针转换为目标实体)。
指针取值与运算的优先级
和c一样,&
表示取地址,*
表示取实体
package main
import (
"fmt"
)
func main() {
d := struct {
s string
x int
}{"abc", 100}
p := &d //p获得d的地址
(*p).x += 100 //应用括号将"*p"优先运算,否则会先运算"p.x",而指针没有x部分,所以会报错
fmt.Printf("%#v\n", d)
}
任意指针间的类型转换
可以在 unsafe.Pointer
和任意类型指针间进行转换。(但有运行出错的风险!)
package main
import (
"fmt"
"unsafe"
)
func main() {
x := 0x12345678
p := unsafe.Pointer(&x) // *int -> Pointer
fmt.Println(x, p)
n := (*[4]byte)(p) // Pointer -> *[4]byte
for i := 0; i < len(n); i++ {
fmt.Printf("%v ", n[i])
}
t := (*string)(q) // panic: runtime error: invalid memory address or nil pointer dereference
fmt.Println(*t)
}
/*
输出:
305419896 0xc000018028
120 86 52 18
*/
自定义类型
未命名类型
可将类型分为命名和未命名两大类。命名类型包括 bool
、int
、string
等,而 array
、slice
、map
等和具体元素类型、长度等有关,属于未命名类型。
具有相同声明的未命名类型被视为同一类型。
- 具有相同基类型的指针。
- 具有相同元素类型和长度的
array
。 - 具有相同元素类型的
slice
。 - 具有相同键值类型的
map
。 - 具有相同元素类型和传送方向的
channel
。 - 具有相同字段序列 (字段名、类型、标签、顺序) 的匿名
struct
。 - 签名相同 (参数和返回值,不包括参数名称) 的
function
。 - 方法集相同 (方法名、方法签名相同,和次序无关) 的
interface
。
package main
func main() {
//声明两种未命名类型的变量
var a struct { x int }
var b struct { x int }
//可以相互赋值,说明是同一类型
b=a
a=b
}
全局自定义类型
使用关键字type
在全局或函数内定义新类型
type bigint int64
新类型不是原类型的别名,除拥有相同数据存储结构外,它们之间没有任何关系,不会持有原类型任何信息。除非目标类型是未命名类型,否则必须显式转换。
var a int64 = 100
var b bigint = bigint(a)//必须显式转换
b = bigint(a)//必须显式转换
a = 200 //常量不需要转换
b = 300 //常量不需要转换
参考
Q.E.D.