指针

和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 
*/

自定义类型

未命名类型

可将类型分为命名和未命名两大类。命名类型包括 boolintstring 等,而 arrayslicemap 等和具体元素类型、长度等有关,属于未命名类型。

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

  • 具有相同基类型的指针。
  • 具有相同元素类型和长度的 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 //常量不需要转换

参考

Go 边看边练

Q.E.D.


此 生 无 悔 恋 真 白 ,来 世 愿 入 樱 花 庄 。