什么"动态类型"在Go界面中意味着什么?

时间:2015-10-26 02:04:48

标签: go

前进的道路:Go Go编程语言的简要介绍(Ivo Balbaert)包含了我不太了解的这句话:

  

接口类型可以包含对实现接口的任何类型的实例的引用(接口具有所谓的动态类型)

这是一个什么样的例子,为什么这很有用?

3 个答案:

答案 0 :(得分:2)

假设你有一个界面:

type I interface{ F() }

所述界面的两个实现:

type S struct{}
func (S) F() { }

type T struct{}
func (T) F() { }

然后:

var x I
x = S{}

现在,x的静态类型为I,其动态类型为S

您可以重新指定x实现I的其他类型的值:

x = T{}

现在x的静态类型仍为I(它永远不会改变),其动态类型为T

IOW:接口值的动态类型是最初转换为接口类型的值的类型。

答案 1 :(得分:1)

<强>定义

  

界面具有所谓的动态类型

动态类型意味着它可以保存对不同类型的引用(例如string,int,...),并且它可以在运行时更改,而静态类型在编译时检查并且不能更改。

然而,该书给出的定义受到质疑。根据官方Golang网站:

  

有些人说Go的界面是动态输入的,但这是误导性的。它们是静态类型的:接口类型的变量始终具有相同的静态类型,即使在运行时存储在接口变量中的值可能会更改类型,该值也始终满足接口。

Source

示例

尽管界面不是真正的动态类型,但以下是如何使用它们。

假设您有以下界面。

type Locker interface {
  Lock()
  Unlock()
}

实际上Locker来自sync包。

现在,如果您创建两个实现Locker接口定义的函数的结构。换句话说,如果您履行了Locker合同,则可以将结构FooBar用作Locker界面。

type Foo struct {
  A string
}

func (f *Foo) String() string {
  return f.A
}

func (f *Foo) Lock() {
  // ...
}

func (f *Foo) Unlock() {
  // ...
}

type Bar struct {}

func (b *Bar) Lock() {
  // ...
}

func (b *Bar) Unlock() {
  // ...
}

所以给出你给出的定义:

  

接口类型可以包含对实现接口的任何类型的实例的引用(接口具有所谓的动态类型)

可以翻译成:

  

Locker(接口)类型可以包含对实现其合同的任何类型的实例的引用(例如Foo,Bar,...)。

代码中的含义:

var lock Locker

lock = &Foo{"Foo"} // We assign an instance of type Foo to a Locker var
lock.Lock() // We can call all functions defined by the interface Locker
lock.Unlock()
lock.String() // This won't work because the Locker interface does not define the String() function, even though Foo implements it. 

lock = &Bar{}
lock.Lock()

在上面的示例中,我们可以看到变量lock包含对不同类型的引用,但它并不是真正动态的,因为将类型分配给lock的条件是它的类型符合Locker合同。{{1}}那部分是在编译时定义的。

为什么有用?

这篇文章将解释为什么界面比我更有用。 https://softwareengineering.stackexchange.com/questions/108240/why-are-interfaces-useful

答案 2 :(得分:0)

每个变量都有一个类型。该类型是静态类型(int,string,bool,map,struct,slice等)或接口类型。

接口可以通过任何静态类型实现(通常使用别名类型)。

接口类型的变量实际上存储在两个部分中。第一部分是底层静态类型的符号名称。第二部分是静态类型格式的数据。

因此,如果一个变量被声明为接口类型,那么这意味着它的类型是动态的,因为底层类型最终可能是实现该接口的任何静态类型。

通常,此模式的用处是从某些共享行为定义一类类型的扩展行为。这样做可以在任何特定情况下封装您关心的功能,而不必担心给定类型的细节。例如,任何Reader都可以读取,一旦你决定拥有一个阅读器,你就不必担心底层类型可能具有的所有其他方法,这意味着你可以轻松定义一个使用的函数。 任何读者。

这与多态性接近,并且分享了大部分好处。