Go-类型系统

本文深入探讨Go语言的类型系统,包括命名类型和未命名类型、底层类型、类型相同、类型强制转换、方法系统和函数类型。介绍了自定义类型、方法调用、组合以及函数类型的概念,帮助理解Go语言中类型和方法的使用方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文内容基于《Go语言核心编程》,李文塔著。


1 类型系统

1.1 类型简介

1.1.1 命名类型和未命名类型

1.1.2 底层类型

1.1.3 类型相同

1.1.4 类型强制转换

1.2 类型方法

1.2.1 自定义类型

1.2.2 方法

1.3 方法调用

1.3.1 一般调用

1.3.2 方法值

1.3.3 方法表达式

1.3.4 方法集

1.3.5 值调用和表达式调用的方法集

1.4 组合

1.5 函数类型

1.5.1 函数类型

1.5.2 函数签名

1.5.3 函数声明

1.5.4 函数类型的意义


1 类型系统

Go语言的类型系统可以分为命名类型、非命名类型、底层类型、动态类型和静态类型等。

1.1 类型简介

1.1.1 命名类型和未命名类型

命名类型:类型可以通过标识符来表示,这种类型称为命名类型,Go语言的基本类型中有20个预声明简单类型和用户自定义类型都是命名类型。

未命名类型:一个类型由预声明类型、关键字和操作符组合而成,这个类型成为未命名类型,又称为类型字面量,Go语言的基本类型中的复合类型都是未命名类型(数组、切片、字典、通道、指针、函数字面量、结构、接口),注意这里指的是没有使用type格式来定义的。

type Person struct {
	name string
	age int
}

func main() {
	// 未命名类型
	a := struct {
		name string
		age int
	}{"张三", 18}

	// 命名类型
	b := Person{
		name: "李四",
		age: 20,
	}

	fmt.Printf("a = %T\n", a)		// a = struct { name string; age int }
	fmt.Printf("b = %T\n", b)		// b = main.Person
}

  • 基本类型=简单类型+复合类型;
  • 命名类型=预声明类型+自定义类型;
  • 预声明类型=简单类型;
  • 自定义类型的old_type可以是预声明类型、自定义类型和未命名类型中的一种;
  • 未命名类型=类型字面量=复合类型。

1.1.2 底层类型

所有类型都有一个底层类型:

  • 预声明类型和未命名类型的底层类型是它们自身;
  • 自定义类型中的new_type的底层类型是逐层递归向下查找的,知道查到的old_type是预声明类型或未命名类型为止。
// T1和T2的底层类型是string
type T1 string
type T2 T1

// T3和T4的底层类型是[]string
type T3 []string
type T4 T3

// T5和T6的底层类型是[]T1
type T5 []T1
type T6 T5

1.1.3 类型相同

两个类型是否相同,参考如下:

  • 两个命名类型相同的条件是两个类型声明的语句完全相同;
  • 命名类型和未命名类型永远不相同;
  • 两个未命名类型相同的条件是它们的类型声明字面量的结构相同,并且内部元素的类型相同;
  • 通过类型别名语句声明的两个类型相同(type T1 = T2)。

引入别名主要有如下原因:

  • 为了解决新旧包的迁移兼容问题,比如context包先前并不在标准库里面,后面迁移到了标准库;
  • Go的按包进行隔离的机制不太精细,有时我们需要将大包划分为几个小包进行开发,但需要在大包里面暴露全部的类型给使用者;
  • 解决新旧类型的迁移问题,新类型先是旧类型的别名,后续的软件都基于新类型编程,在合适的时间将新类型升级为和旧类型不兼容,常用于软件的柔性升级。

1.1.4 类型强制转换

字符串和字节切片之间的转换最为常见:

  • 数值类型和string类型之间的相互转换可能造成值部分丢失,其他的转换仅是类型的转换,不会造成值的改变;
  • string和数字之间的转换可以使用标准库strconv;
  • Go语言没有语言机制支持指针和interger之间的直接转换,可以使用标准库中的unsafe包进行处理。
// 顺便体会[]byte和[]rune的区别(中文占几个字节?)
func main() {
	s := "hello 世界"
	var a []byte
	a = []byte(s)
	fmt.Printf("string -> []byte = %v -> %v\n", s, a)		// string -> []byte = hello 世界 -> [104 101 108 108 111 32 228 184 150 231 149 140]

	var b string
	b = string(a)
	fmt.Printf("[]byte -> string = %v -> %v\n", a, b)		// []byte -> string = [104 101 108 108 111 32 228 184 150 231 149 140] -> hello 世界

	var c []rune
	c = []rune(s)
	fmt.Printf("string -> []rune =
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值