Go中,类型断语和类型转化是一个令人困惑的工作,他们似乎都在做相同的工作。

下面是一个类型断语的比方:

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

接着看一个类型转化的比方:

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

最明显的不同点是他们具有不同的语法(variable.(type) vs type(variable) )。接下来,咱们进一步去研讨。

类型断语

顾名思义,类型断语用于断语变量是属于某种类型。类型断语只能发生在interface{}类型上。
上面类型断语的比方,greeting是一个interface{}类型,咱们为其分配了一个字符串。现在,咱们能够认为greeting实际上是一个string,可是对外展现的是一个interface{}
假如咱们想获取greeting的原始类型,那么咱们能够断语它是个string,而且此断语操作会回来其string类型。

go 类型断言 类型转换
这意味着在做类型断语的时分,咱们应该知道任何变量的根底类型。可是状况并非总是这样的,这便是为什么类型断语操作实际上还回来了第二个可选值的原因。

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

第二个值是一个布尔值,假如断语正确,回来true,不然回来false。
另外,类型断语是在程序运行时履行。

类型判别

类型判别是一个很有用的构造。当你不确定interface{}真实类型的时分,能够运用它。

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{}转化成int类型或者string类型。可是greeting的类型是固定,而且和初始化期间声明时的内容相同。
当咱们把greeting分配给interface{}类型的时分,请勿修正其原始类型。相同,当咱们断语类型的时分,咱们仅仅运用了原始类型功能,而不是运用interface揭露的有限办法。

类型转化

首先,咱们花点时刻了解一下什么是 “类型”。在Go每种类型都定义了两件事:

  • 变量的存储方法 (存储结构)
  • 你能够运用变量做什么 (能够运用的办法和函数)

这里介绍了底子类型,包括了stringint。以及一些复合类型,比方struct``map``arrayslice。 你能够从底子类型或经过创建复合类型来声明一个新类型。

// `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上面声明一个新办法)。 由于myInt的类型根据int,意味着他们的底层根底类型是相同的。因而这些类型的变量能够彼此转化。

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

上面i的类型是myInt,originalInt的类型是int

go 类型断言 类型转换

什么时分运用类型转化?

只有当根底数据结构类型相同,类型之间才能够彼此转化。来看一个运用struct比方。

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
}

go 类型断言 类型转换
因而他们能够彼此转化。 type可用于声明具有相同数据结构的多种类型。 这仅仅意味着childperson根据相同的数据结构 (类似于之前的intmyInt)。

类型为什么称为转化

就像上面说的,虽然不同类型的根底结构可能相同,可是他们可能也具有不同的限制和办法。当咱们从一种类型转化成另一种类型时,会改变对类型的处理方法,而不是像类型断语那样仅揭露其根底类型,这便是他们本质的不同。
假如尝试去转化过错的类型,类型转化会提示编译过错,这和类型断语所提供的运行时经过回来值判别过错,完全相反。

类型结论

类型断语和类型转化有着比语法层面上更底子的区别。它还强调了在Go接口类型 (interface) 和非接口类型之间的区别。 接口类型没有任何数据结构,而是揭露了已有的详细类型 (具有底层数据结构) 的一些办法。
类型断语引出了接口的详细类型,而类型转化改变了在具有相同数据结构的两个详细类型之间运用变量的方法。