type 关键字
Type关键字在Go语言中作用很重要,他主要用来实现两个功能:
go
【自定义类型】
自定义类型底层是一种类型,但是不会拥有底层类型的方法。
自定义类型与底层类型相比是一种新类型,二者之间需要显式类型转换。
//语法
type 自定义类型 底层类型
【类型别名】
类型别名就是为原类型取个新名字,完整拥有原类型的方法。
//语法
type 类型别名 = 原类型
自定义类型
基本语法
go
type 自定义类型 底层类型;
声明自定义类型并赋值
声明自定义类型
在Go 语言中,基础类型有下面几种:
go
bool byte complex64 complex128 error float32 float64
int int8 int16 int32 int64 rune string
uint uint8 uint16 uint32 uint64 uintptr
使用 type 关键字可以定义我们自己的类型,如我们可以使用type定义一个新的结构体,也可以基于一个已经存在的类型来定义新类型,然后就可以在我们的代码中使用新的类型名字,这称为自定义类型,如:
go
type IZ int
这里IZ就是完全是一种新类型,然后我们可以使用下面的方式声明变量:
go
var a IZ =5
这里我们可以看到 int 是变量 a 的底层类型,这也使得它们之间存在相互转换的可能。
理解
在已有的类型上映射出一个新类型,该类型可以存储与底层变量一样的值。
sh
1.自定义类型不拥有原类型的方法,只是用来存储原类型一样的值。
好比于我们不满足golang
之前对整数的处理方法,于是我们定义一种新类型来存储整数,然后重新给他加方法。
在 type IZ int
中,IZ 就是基于int 类型构建的新类型,这称为自定义类型。然后就可以使用 IZ 来操作 int 类型的数据。
多个自定义类型声明
如果我们有多个类型需要定义,可以使用因式分解关键字的方式,例如:
Go
type (
IZ int
FZ float64
STR string
)
显式转换
自定义类型与原类型已经分道扬镳了,虽然变量的形式长的一样,但是他们属于不同的类型,拥有着不同的方法。
就好比亚洲人,日本人和韩国人虽然都属于亚洲人,但是实际上属于不同国家,如果要调整国籍需要显式转换。
5是整数,
int
和我们的自定义类型IZ
都是整数,但实际上是不同类型,需要也需要显式转换。
举例
go
type IZ int
var a IZ = 5
//虽然a的值是5,也是整数,但是他已经属于IZ,
//如果我们要将他给int,就需要显式转换
b := int(a)
官方解释
每个值在经过编译后都必须属于某个类型(编译器必须能够推断出所有值的类型),因为 Go 语言是一种静态类型语言。
在必要以及可行的情况下,一个类型的值可以被转换成另一种类型的值。
由于 Go 语言不存在隐式类型转换,因此所有的转换都必须显式说明,就像调用一个函数一样(类型在这里的作用可以看作是一种函数):
go
//强制转换的语法
valueOfTypeB = typeB(valueOfTypeA)
//中文
类型 B 的值 = 类型 B(类型 A 的值)
方法验证
自定义类型不具备原类型的方法。
go
package struct_knowledge
import "fmt"
//基础类型结构体
type Age struct{
age int
}
//自定义类型
type Myage Age
//我们给Age类型添加一个方法
func (a Age) IsAdult(){
if(a.age>=18){
fmt.Println("已经成年")
}else{
fmt.Println("未成年")
}
}
//验证自定义类型是否有底层类型的方法
func CustomerType(){
var age1 = Age{
age:19,
}
var age2 = Myage{
age:20,
}
age1.IsAdult()
/*
报错:
age2.IsAdult undefined
type Myage has no field or method IsAdult
*/
// age2.IsAdult()
}
通过Type 关键字在原有类型基础上构造出一个新类型,我们需要针对新类型来重新创建新方法。
自定义类型存在意义
我们不能给私有类型添加方法,例如
go
bool byte complex64 complex128 error float32 float64
int int8 int16 int32 int64 rune string
uint uint8 uint16 uint32 uint64 uintptr
他们都是小写开头,也就是golang
的本地私有类型,如果我们向给他们添加方法就会报错,例如:
golang
的本地私有类型,指的是上述这些golang自带类型。我们自己定义的私有类型不算。
go
//给golang的私有类型添加方法会报错
// cannot define new methods on non-local type int
func (a int) IsOdd()bool{
if(a%2==0){
fmt.Println("a是偶数")
return false
}else{
fmt.Println("a是奇数")
return true
}
}
报错信息
go
cannot define new methods on non-local type int
所以我们想给原类型添加新方法只能用自定义类型来映射底层类型。
后续说到的类型别名,本质上是给底层类型重命名,所以无法解决这个问题。
类型别名
基本语法
go
type 类型别名 = 原类型名;
别名类型和原类型,这两个类型可以视为完全一致,能交换使用。
我们把
type 类型别名
定义的新类型叫做别名类型。
举例
go
package type_knowledge
import "fmt"
type Myint = int
func GetInt(){
var a Myint = 20
var b int
//不需要类型转换,因为二者本质上是同一类型
b = a
fmt.Printf("b的值为%d\n",b)
}
理解
就好比于,你在中国叫张三
,去了国外取了个英文名Sam
,本质上还是一个人。
方法验证
别名类型本质上还是原类型,所以拥有原类型的一切方法与性质。
本地类型不允许添加方法
go
type Myint = int
//给golang的私有类型添加方法会报错
// cannot define new methods on non-local type int
func (a Myint) IsOdd()bool{
if(a%2==0){
fmt.Println("a是偶数")
return false
}else{
fmt.Println("a是奇数")
return true
}
}
从报错信息可知,golang
是凭借原类型来识别别名类型的。
测试方法
go
package type_knowledge
import "fmt"
type Book struct{
price int
}
type MyBook = Book
func (a Book) IsCheap() bool{
if(a.price>=20){
fmt.Println("The book is expensive")
return false
}else{
fmt.Println("The book is cheap")
return true
}
}
func OtherNameType(){
book1 := Book{
price: 25,
}
book2 := MyBook{
price: 30,
}
book1.IsCheap()
book2.IsCheap()
}
别名类型拥有原类型的所有方法。
注意事项
由于别名类型本质上就是原类型,所以我们给别名类型添加方法也就是在给原类型添加方法。
别名类型存在的意义
字符在计算机中是用数字存储的,所以没有必要再创造一种新类型,所以golang
存储字符的类型的底层源码为:
go
type byte = int8
type rune = int32