Go 中的类型断言和类型转换的差别()

在Go中,类型断言和类型转换似乎是一个令人困惑的话题,因为它们似乎都在做相同的事情。

在本文中,我们将看到断言和转换实际上有很大的不同,并且深入了解了在Go中使用它们时会发生什么。

首先,让我们看看它们的写法

这是Go中的类型断言:

var greeting interface{} = "hello world"
greetingStr := greeting.(string)

这是类型转换:

greeting := []byte("hello world")
greetingStr := string(greeting)

最明显的不同是它们具有不同的语法(variable.(type) vs  type(variable))。让我们详细研究每种情况。

类型断言

顾名思义,类型断言用于 断言 判断一个变量是某种类型。类型断言 只能在接口上发生。

在上面的类型断言示例中, greeting是一个interface{}类型,我们为其分配了一个字符串。现在,我们可以说greeting实际上是一个string,但是向我们公开的接口是 interface{}

如果我们想要获取原始类型,greeting 则可以断言它是一个字符串,并且此断言返回其原始 string 类型。

type assertions obtain the original type from the interface

这意味着在进行类型声明时,我们应该知道变量的基础类型,但情况并非总是如此。这就是为什么类型断言表达式实际上返回第二个可选值的原因:

var greeting interface{} = "42"
greetingStr, ok := greeting.(string)

第二个值ok是一个布尔值,如果我们的断言正确,则为true,否则为false。

这也意味着类型声明在运行时执行 。

类型Switch

类型switch语法是一个有用的构造,可以在不确定接口类型时使用:

var greeting interface{} = 42

switch g := greeting.(type) {
  case string:
    fmt.Println("g is a string with length", len(g))
  case int:
    fmt.Println("g is an integer, whose value is", g)
  default:
    fmt.Println("I don't know what g is")
}

为什么要断言?

在上面的例子中,它可能看起来像你“转换”的类型greetinginterface{}intstring。但是,的类型greeting是固定的,并且与初始化期间声明的相同。

分配greeting接口类型时,请勿更改其基础类型。 同样声明其类型时,您只是在使用整个原始类型功能,而不是使用接口公开的有限方法。

类型转换

首先,让我们花点时间了解一下什么是“类型”。Go中的每种类型都定义了两件事:

  1. 变量的存储方式(基础数据结构)
  2. 您可以使用变量做什么(可以使用的方法和函数)

有几个基本类型,其中stringint包括在内。以及复合类型,包括Struct、Map、Array和Slice。

您可以从基本类型或通过创建复合类型来声明新类型:

// myInt是一个新的基础类型`int`
type myInt int

// AddOne方法是myInt使用的,但是没有声明给int
func (i myInt) AddOne() myInt { return i + 1}

func main() {
    var i myInt = 4
    fmt.Println(i.AddOne())
}

声明myInt类型时,我们将变量结构基于基本类型int,但更改了我们可以对myInt类型变量执行的操作(通过在其上声明新方法)。

由于myInt的底层结构是类似int,这些类型的变量可以彼此之间转换:

var i myInt = 4
originalInt := int(i)

这个imyInt类型,但是originalIntint类型。

types can be converted as long as they have the same underlying data structure

什么时候可以使用类型转换?

如果基础结构相同,类型之间可以相互转换 。让我们来看一个使用结构的示例:

type person struct {
    name string
    age int
}

type child struct {
    name string
    age int
}

type pet {
  name string
}

func main() {
    bob := person{
        name: "bob",
        age: 15,
        }
  babyBob := child(bob)
  // "babyBob := pet(bob)" 会导致编译错误
    fmt.Println(bob, babyBob)
}

在这里,person并且child具有相同的数据结构,即:

struct {
    name string
    age int
}

因此,它们可以相互转换。

types with different underlying data structures cannot be converted between one another

type可用于声明具有相同底层结构的多种类型:

type pet person

这仅表示child基于相同的结构person(类似于之前的整数示例)

在这里运行这个例子

为什么称为转换

如前所述,即使不同类型的底层结构可能相同,它们也具有不同的限制和定义的方法。当您从一种类型转换为另一种类型时,您将改变对类型的处理方式,而不仅仅是像类型声明中那样公开其基础类型。

如果您尝试转换为错误的类型,则类型转换还会给您带来编译错误,这与ok类型声明所提供的运行时错误和可选返回值相反 。

结论

类型断言和类型转换之间的区别比语法上的区别更根本。它还强调了Go中接口类型和非接口(或具体)类型之间的区别。

interface类型没有任何基础数据结构,而是暴露了一个预先存在的具体类型的一些方法(它具有一个基础数据结构)。

类型断言获得了接口基础的具体类型,而类型转换改变了两个具有相同结构的类型之间的使用方式。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://www.sohamkamani.com/golang/type-...

译文地址:https://learnku.com/go/t/52387

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 2

机翻味太重

1年前 评论
mtcurry 4周前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!