美文网首页Go语言实践编程语言爱好者
《Go in Action》第五章 类型系统

《Go in Action》第五章 类型系统

作者: Mr_Hospital | 来源:发表于2019-11-18 21:54 被阅读0次

首先,go是一门静态类型语言。即编译器知道每一个值的类型。

如何定义一个类型?

A: 使用关键字type和struct:

type user struct {
  name string
  email string
  ext int
  privileged bool
}

注意每一行没有逗号。
创建一个类型的值:

var rain user
lisa := user {
  nae: "Lisa",
  email: "lisa@email.com",
  ext: 123,
  privileged: true,
}

lisa1 := user{"Lisa", "lisa@email.com", 123, true} //最后一个逗号没有

注意每一行都有逗号,最后一行也有。

struct的属性可以是struct类型:

type admin struct {
  u user
  level string
}

fred := admin {
  u: user {
    name: "Fred",
    email: "fred@email.com",
    ext: 123,
    privileged: true,
  },
  level: "super",
}

另一种创建类型的方式:

type Duration int64

注意此时,编译器认为Duration和int64不是同一种类型。此时,我们称int64是Duration的"base type"

方法

方法是一种给类型增加行为的方式。

type user struct {
  name string
  email string
}

func (u user) notify() {
  fmt.Printf("Sending User Email to %s<%s>\n", u.name, u.email)
}

func (u *user) changeEmail(email string) {
  u.email = email
}

func和方法名之间的参数称为“receiver"。当一个函数具有receiver的时候,我们就称该函数为方法。

receiver具有两种类型:

  • value receiver。即值传递。
  • pointer receiver。传递的是类型的指针

两个不同类型的方法都可以被类型的值或者指针调用。如:

bill := user{"bill", "bill@email.com"}
bill.notify()

lisa := &user{"lisa", "lisa@email.com"}
lisa.changeEmail("lisayou")
lisa.notify()

go会自动进行(*lisa).notify()(&bill).changeEmail()的转换。

一般来说,当使用value receiver的时候表明不需要改变值,使用pointer receiver的时候需要改变值。

接口

A: 使用type和interface定义接口:

type notifier interface{
  notify()
}

注意这里没有定义接口的返回值和参数,因为返回值和参数都没有。

Q: 如何使用接口?

A: 见代码:

func sendNotification(n notifier) {
  n.notify()
}

Q: 如何实现接口?

A: 类型的方法具有同接口一样的名字、参数和返回值,就认为该类型实现了接口。无需显示声明。
比如:

type user struct {
  name string
  email string
}

func (u user) notify(){

}

此时user实现了notifier接口。

Q: point receiver的方法算接口实现吗?

A: 看一个例子:

type user struct {
  name string
  email string
}
func (u *user) notify(){
}

此时user算是实现了notifier了吗?
先来了解一下methods sets:

Method sets define the set of methods that are associated with values or pointers of a given type. The type of receiver used will determine whether a method is associated with a value, pointer, or both.

method sets定义了一个值或者指针类型的方法集。方法的receiver的类型决定了一个方法是同值、指针或者两者都进行了关联。听起来一头雾水。

image.png

这个表的意思是:

  • 类型T的值的method sets仅包含value receiver的方法
  • 类型*T的值的method sets既包含value receiver的方法也包含pointer receiver的方法

从method receiver的角度来看:


image.png

这个的意思就是:

  • 如果使用pointer receiver实现了某个接口,那么实际上是该类型的指针实现了该接口
  • 如果使用value receiver实现了某个接口,那么该类型的值和指针类型都实现了该接口

上面的代码的方法是pointer receiver,所以仅有user类型的指针类型实现了接口。

为什么这么定义,是因为并不是总能获取某个值的地址:

type duration int

func (d *duration) pretty() string {
  return fmt.Sprintf("Duration: %d", *d)
}

func main() {
  duration(42).pretty()
}

Q: 什么是多态?

A: 简单来说:多态就是,声明的时候是接口,传入的时候是该接口的实现。不同的实现具有不同的行为。

Q: type embedding是什么?

A: 先看原文:

This is accomplished through type embedding. It works by taking an existing type and declaring that type within the declaration of a new struct type. The type that is embedded is then called an inner type of the new outer type.

简单来说,就是将一个已经存在的类型(type)放在一个新类型中声明。
被嵌入的类型称为inner type,新类型称为outer type。

有什么作用呢?

Through inner type promotion, identifiers from the inner type are promoted up to the outer type. These promoted identifiers become part of the outer type as if they were declared explicitly by the type itself.

简单来说,inner type的属性和方法就像是outer type自己定义的一样。同时outer type也可以覆盖inner type的属性和方法。看一个例子:

package main

import (
  "fmt"
)

type user struct {
  name string
  emaill string
}

func (u *user) notify() {
  fmt.Printf("Sending user email to %s<%s>\n", u.name, u.email)
}

type admin struct {
  user  // Embedded Type
  level string
}

func main() {
  ad := admin{
    user: user{
      name: "john smith",
      email: "john@yahoo.com",
    },
    level: "super",
  }
  ad.user.notify()
  ad.notify()
}

我们也可以覆盖user里面的方法,比如:

func (a *admin) notify() {
  fmt.Printf("Sending admin email to %s<%s>\n", a.name, a.email)
}

此时,由于admin内嵌了user,user实现了notifier接口,因此admin其实也实现了notifier接口。

导出和不导出identifiers

简单来说,就是包里面的小写字母开头的标识符是不导出的,大写开头的是导出的。
先来看一个例子:

// counters/counters.go
package counters

type alertCounter int

func New(value int) alertCounter {
  return alertCounter(value)
}

// listing68.go
package main

import (
  "fmt"
  "github.com/goinaction/code/chapter5/listing68/counters"
)

func main() {
  counter := counters.New(10)
  fmt.Printf("Counter: %d\n", counter)
}

在counters.go里面的alertCounter是小写字母开头,因此该identifer没有导出,不能在下个文件的main函数里面使用。但是New方法是导出了的。因此,main函数里面的代码没有错误。

但是有个问题,alertCounter没有导出,怎么可以使用呢?
见原文:

This is possible for two reasons. First, identifiers are exported or unexported, not values. Second, the short variable declaration operator is capable of inferring the type and creating a variable of the unexported type. You can never explicitly create a variable of an unexported type, but the short variable declaration operator can.

简单来说:
1,导出或者不导出的是identifiers,不是values。也就是说小写字母的类型的值是可以在package外使用的;
2,不能显式使用未导出的identifier,但是可以隐式使用。也就是使用:=是可以的。

看一个完整版:

// entities/entities.go
package entities

type user struct{
  Name string
  Email string
}

type admin struct{
  user
  Rights int
}

// listing74.go
package main

import (
  "fmt"
  "github.com/goinaction/code/chapter5/listing74/entities"
)

func main() {
  a := entities.Admin{
    Rights: 10,
  }
  
  a.Name = "Bill"
  a.Email = "bill@email.com"
  fmt.Printf("User: %v\n", a)
}

相关文章

  • 《Go in Action》第五章 类型系统

    首先,go是一门静态类型语言。即编译器知道每一个值的类型。 如何定义一个类型? A: 使用关键字type和stru...

  • selenium IDE 指令

    操作类型——Action 浏览器操作 open(https://www.sogou.com/) 打开url。 go...

  • 《GO in action》第5章(Go语言的类型系统)读书笔记

    5.1 用户定义的类型 不使用字段名创建结构类型的值,这咱形式下值的顺序很重要。 两种不同类型的值即便相互兼容,也...

  • ACTION!GO!GO!GO!

  • Go语言的类型系统概览

    本文将介绍go语言中的各种类型和go类型系统中的各种概念。 不知道这些概念,将很难理解go语言。 概念:基本类型 ...

  • 玩转Golang之Struct结构体

    先介绍一下go语言的类型系统 Golang中的类型系统 类型系统是指一个语言的类型体系结构。一个典型的类型系统通常...

  • Go开发关键技术指南:Interfaces

    Interfaces Go在类型和接口上的思考是: Go类型系统[#type-system]并不是一般意义的OO,...

  • Go的类型系统

    1、什么是类型系统 类型系统是 一个语言的类型体系结构。 类型系统才是一门编程语言的地基,它的地位至关重要。 Go...

  • Go语言类型系统

    用户定义的类型 使用结构类型变量,并初始化为其零值 当声明变量时,这个变量对应的值总是会被初始化。 使用结构字面量...

  • golang读书笔记(五)

    参考了《Go in Action》、《Go 网络编程:使用 Handler 和 HandlerFunc[https...

网友评论

    本文标题:《Go in Action》第五章 类型系统

    本文链接:https://www.haomeiwen.com/subject/eakiictx.html