5. Go 语言的类型系统(Go Tutorial)
来源:互联网 发布:同步带传动计算软件 编辑:程序博客网 时间:2024/06/05 16:42
Go 语言的类型系统
- 1 用户定义的类型
- 11 使用 struct 关键字声明结构类型
- 12 基于一个已有类型将其作为新类型的说明
- 2 方法
- 3 类型的本质
- 31 内置类型
- 32 引用类型
- 33 结构类型
- 4 接口
- 41 标准库
- 42 实现
- 43 方法集
- 44 多态
- 5 嵌入类型
- 6 公开或未公开的标识符
- 7 小结
Go 语言是一种静态类型的编程语言,这意味着编译器在编译时需要事先知道变量的类型,这样有助于编译器对代码的一些优化,提高执行效率。
5.1 用户定义的类型
Go 语言里声明用户自定义类型有两种方式:
- 使用关键字 struct 创建结构类型
- 基于一个已有类型,将其作为新类型的类型说明
5.1.1 使用 struct 关键字声明结构类型
声明一个结构类型
type user struct { name string email string age int isMale bool}
使用结构类型声明变量并初始化零值
var bill user
任何时候,创建一个变量并初始化为零值,习惯上是使用关键字 var。如果变量被初始化为非零值,就配合结构字面量和短变量声明操作符来创建变量(即 := )
使用结构字面量来声明一个结构类型的变量
lisa := user{ name: "lisa", email: "lisa@email.com" age: 22, isMale: false,}
不使用字段名,创建结构类型的值
// 这种形式下,值的顺序很重要,必须要和结构声明中的顺序一致,另外最后也不需要使用 ',' 结尾// 可以部分初始化,未初始化的部分为零值lisa := {"lias", "lisa@eamil.com", 22, false}
使用其他结构类型声明字段
type admin struct { person user level string}
使用结构字面量来创建字段的值
fred := admin { person: user { name: "fred", email: "fred@email.com" age: 22, isMale: true, }, level: "super",}
5.1.2 基于一个已有类型,将其作为新类型的说明
当需要一个可以用已有类型表示的新类型的时候,这种方法会很好用。
基于 int64 声明一个新类型
type Duration int64
5.2 方法
方法能给用户定义的类型添加新的行为。
方法实际上也是函数,只是在声明时,在关键字 func 和方法名之间增加了一个参数。
// Sample program to show how to declare methods and how the Go// compiler supports them.package mainimport ( "fmt")// user defines a user in the program.type user struct { name string email string}// notify implements a method with a value receiver.func (u user) notify() { fmt.Printf("Sending User Email To %s<%s>\n", u.name, u.email)}// changeEmail implements a method with a pointer receiver.func (u *user) changeEmail(email string) { u.email = email}// main is the entry point for the application.func main() { // Values of type user can be used to call methods // declared with a value receiver. bill := user{"Bill", "bill@email.com"} bill.notify() // Pointers of type user can also be used to call methods // declared with a value receiver. lisa := &user{"Lisa", "lisa@email.com"} lisa.notify() // Values of type user can be used to call methods // declared with a pointer receiver. bill.changeEmail("bill@newdomain.com") bill.notify() // Pointers of type user can be used to call methods // declared with a pointer receiver. lisa.changeEmail("lisa@newdomain.com") lisa.notify()}
5.3 类型的本质
类型的本质主要体现在,如果给这个类型增加或删除某个值,是创建一个新值,还是在更改当前值。这也关系到这个类型在函数之间到底时用值传递还是指针传递。
5.3.1 内置类型
内置类型时语言提供的一组类型,比如数值类型、字符串类型、布尔类型和数组等。
这些类型本质上是原始类型,在函数或方法间传递时,传递的是对应值的副本
5.3.2 引用类型
Go 语言里的引用类型有如下几个:切片、映射、通道、接口和函数类型。
这些类型在函数间传递的是指针,共享底层数据结构。
5.3.3 结构类型
结构类型可以用来描述一组数据值,这组值的本质既可以是原始的,也可以是非原始的。
5.4 接口
多态是指代码可以根据类型的具体实现采取不同的行为。
如果一个类型实现了某个接口,所有使用这个接口的地方,都可以支持这种类型的值。
5.4.1 标准库
// Sample program to show how to write a simple version of curl using// the io.Reader and io.Writer interface support.package mainimport ( "fmt" "io" "net/http" "os")// init is called before main.func init() { if len(os.Args) != 2 { fmt.Println("Usage: ./example2 <url>") os.Exit(-1) }}// main is the entry point for the application.func main() { // Get a response from the web server. r, err := http.Get(os.Args[1]) if err != nil { fmt.Println(err) return } // Copies from the Body to Stdout. io.Copy(os.Stdout, r.Body) if err := r.Body.Close(); err != nil { fmt.Println(err) }}
5.4.2 实现
接口是用来定义类型的行为。这些被定i的行为不由接口直接实现,而是通过方法由用户定义的类型实现。如果用户定义的类型实现了接口的一组方法之后,那么这个用户定义的类型的值就可以赋给这个接口类型的值。
在这种关系里,用户定义的类型通常称为实体类型。
5.4.3 方法集
方法集定义了接口的接收规则。
// Sample program to show how to use an interface in Go.package mainimport ( "fmt")// notifier is an interface that defined notification// type behavior.type notifier interface { notify()}// user defines a user in the program.type user struct { name string email string}// notify implements a method with a pointer receiver.func (u *user) notify() { fmt.Printf("Sending user email to %s<%s>\n", u.name, u.email)}// main is the entry point for the application.func main() { // Create a value of type User and send a notification. u := user{"Bill", "bill@email.com"} sendNotification(u) // ./listing36.go:32: cannot use u (type user) as type // notifier in argument to sendNotification: // user does not implement notifier // (notify method has pointer receiver)}// sendNotification accepts values that implement the notifier// interface and sends notifications.func sendNotification(n notifier) { n.notify()}
上述代码编译不通过的原因在于:
- 如果使用指针接收者来实现了一个接口,那么只有指向那个类型的指针才能够实现对应的接口
- 如果使用值接收者来实现一个接口,那么那个类型的值和指针都能够实现对应的接口
从方法接收者类型的角度来看方法集
5.4.4 多态
// Sample program to show how polymorphic behavior with interfaces.package mainimport ( "fmt")// notifier is an interface that defines notification// type behavior.type notifier interface { notify()}// user defines a user in the program.type user struct { name string email string}// notify implements the notifier interface with a pointer receiver.func (u *user) notify() { fmt.Printf("Sending user email to %s<%s>\n", u.name, u.email)}// admin defines a admin in the program.type admin struct { name string email string}// notify implements the notifier interface with a pointer receiver.func (a *admin) notify() { fmt.Printf("Sending admin email to %s<%s>\n", a.name, a.email)}// main is the entry point for the application.func main() { // Create a user value and pass it to sendNotification. bill := user{"Bill", "bill@email.com"} sendNotification(&bill) // Create an admin value and pass it to sendNotification. lisa := admin{"Lisa", "lisa@email.com"} sendNotification(&lisa)}// sendNotification accepts values that implement the notifier// interface and sends notifications.func sendNotification(n notifier) { n.notify()}
5.5 嵌入类型
嵌入类型是将已有的类型直接声明在新的结构里,从而实现扩展或修改已有类型的行为。被嵌入的类型被称为新的外部类型的内部类型。
要嵌入一个类型,只需要在外部类型中声明之歌类型的名字就可以了。
内部类型的值以及实现的接口都会自动的提升到外部类型,但当外部类型也有相同的值或者实现了相同的结构时,内部类型将不会提升,但此时仍可以通过内部类型的标识来访问。
// Sample program to show what happens when the outer and inner// type implement the same interface.package mainimport ( "fmt")// notifier is an interface that defined notification// type behavior.type notifier interface { notify()}type person struct { age int gender string}// user defines a user in the program.type user struct { person name string email string}// notify implements a method that can be called via// a value of type user.func (u *user) notify() { fmt.Printf("Sending user email to %s<%s>\n", u.name, u.email)}// admin represents an admin user with privileges.type admin struct { user level string age int}// notify implements a method that can be called via// a value of type Admin.func (a *admin) notify() { fmt.Printf("Sending admin email to %s<%s>\n", a.name, a.email)}// main is the entry point for the application.func main() { // Create an admin user. ad := admin{ user: user{ name: "john smith", email: "john@yahoo.com", person: person{ age: 24, gender: "male", }, }, level: "super", age: 26, } // Send the admin user a notification. // The embedded inner type's implementation of the // interface is NOT "promoted" to the outer type. sendNotification(&ad) // We can access the inner type's method directly. ad.user.notify() // The inner type's method is NOT promoted. ad.notify() fmt.Println(ad.user.person.gender) fmt.Println(ad.person.gender) fmt.Println(ad.gender) fmt.Println(ad.user.person.age) fmt.Println(ad.person.age) fmt.Println(ad.age)}// sendNotification accepts values that implement the notifier// interface and sends notifications.func sendNotification(n notifier) { n.notify()}// Sending admin email to john smith<john@yahoo.com>// Sending user email to john smith<john@yahoo.com>// Sending admin email to john smith<john@yahoo.com>// male// male// male// 24// 24// 26
5.6 公开或未公开的标识符
Go 语言支持公开或隐藏标识符。
当一个标识符的名字以小写字母开头,那么这个标识符就是未公开的,在包外不可见
当一个标识符的名字以大写字母开头,那么这个标识符就是公开的,在包外可见
5.7 小结
- 使用关键字 struct 或通过指定已存在的类型,可以声明用户定义的类型
- 方法提供了一种给用户定义的类型增加行为的方式
- 设计类型时需要确认类型的本质是原始的还是非原始的
- 接口是声明一组行为并支持多态的类型
- 嵌入类型提供了扩展类型的功能,而无需使用继承
- 标识符要么是从包里公开的,要么是在包里未公开的
- 5. Go 语言的类型系统(Go Tutorial)
- Go语言的类型结构
- go语言的struct类型
- Go语言学习5:Go语言的变量类型
- 56.笔记go语言——go的函数类型
- Go语言变量类型
- go语言学习-类型
- go语言基本类型
- Go语言-类型
- Go语言类型转换
- Go 语言方法接受者类型的选择
- Go 语言方法接受者类型的选择
- go语言的类型断言(Type Assertion)
- Go语言 goroutine背后的系统知识
- Go语言学习(十一)面向对象编程-类型系统
- Go语言编程(十一)之类型系统
- Go语言编程(十二)之类型系统初始化
- 1. Hello Go(Go Tutorial)
- C++ 关于回调函数调用具类中的函数
- 文件描述符与流的区别
- D. Substrings
- Android脱壳圣战之---脱掉360加固壳(破解约火包神器的钻石充值功能)
- android studio 修改注释Created by 作者名的方法
- 5. Go 语言的类型系统(Go Tutorial)
- OkHttpClient 上传文件
- Nginx 反向代理下拿到客户端的真实IP
- Redis压力测试报告
- java 8 时间控件
- 机器学习标准教科书PRML的Python实现:最佳读书伴侣
- JD-GUI反编译器无法使用的问题
- tomcat单机多实例部署
- 震撼大数据!80后年薪多少,才能摆脱中年危机?