Go语言中的多态性——它是否存在?

huangapple go评论78阅读模式
英文:

Polymorphism in Go - does it exist?

问题

我正在尝试在Go语言中做一些非常简单的事情:创建一个具有getter和setter方法的接口。但是似乎不允许使用setter方法。

给定以下代码:

package main

import "fmt"

type MyInterfacer interface {
    Get() int
    Set(i int)
}

type MyStruct struct {
    data int
}

func (this MyStruct) Get() int {
    return this.data
}

func (this MyStruct) Set(i int) {
    this.data = i
}

func main() {
    s := MyStruct{123}
    fmt.Println(s.Get())

    s.Set(456)
    fmt.Println(s.Get())

    var mi MyInterfacer = s
    mi.Set(789)
    fmt.Println(mi.Get())
}

Set方法不起作用,因为在func (this MyStruct) Set(i int)中,this MyStruct不是一个指针,而且在函数退出时更改会丢失。但是将其更改为this *MyStruct将无法编译。有没有什么解决方法?

英文:

I am trying to make something real simple on Go: to have an interface with getter and setter methods. And it seems setter methods are not allowed.

Given this code:

package main

import "fmt"

type MyInterfacer interface {
	Get() int
	Set(i int)
}

type MyStruct struct {
	data int
}

func (this MyStruct) Get() int {
	return this.data
}

func (this MyStruct) Set(i int) {
	this.data = i
}

func main() {
	s := MyStruct{123}
	fmt.Println(s.Get())

	s.Set(456)
	fmt.Println(s.Get())

	var mi MyInterfacer = s
	mi.Set(789)
	fmt.Println(mi.Get())
}

Set method does not work, because in func (this MyStruct) Set(i int), this MyStruct is not a pointer, and the changes are lost as soon at the function exits. But making it this *MyStruct would not compile. Is there any workaround?

答案1

得分: 8

这是你代码的修正版本(playground)。虽然不完全是多态,但使用接口是Go语言的良好风格。

package main

import "fmt"

type MyInterfacer interface {
    Get() int
    Set(i int)
}

type MyStruct struct {
    data int
}

func (this *MyStruct) Get() int {
    return this.data
}

func (this *MyStruct) Set(i int) {
    this.data = i
}

func main() {
    s := &MyStruct{123}
    fmt.Println(s.Get())

    s.Set(456)
    fmt.Println(s.Get())

    var mi MyInterfacer = s
    mi.Set(789)
    fmt.Println(mi.Get())
}
英文:

Here is a corrected version of your code (playground). This isn't exactly Polymorphism, but the use of an interface is good Go style.

package main

import "fmt"

type MyInterfacer interface {
	Get() int
	Set(i int)
}

type MyStruct struct {
	data int
}

func (this *MyStruct) Get() int {
	return this.data
}

func (this *MyStruct) Set(i int) {
	this.data = i
}

func main() {
	s := &MyStruct{123}
	fmt.Println(s.Get())

	s.Set(456)
	fmt.Println(s.Get())

	var mi MyInterfacer = s
	mi.Set(789)
	fmt.Println(mi.Get())
}

答案2

得分: 4

我曾经找到了一个关于如何在Go语言中实现多态的示例:

package main

import "fmt"

type Talker interface {
    Talk(words string)
}

type Cat struct {
    name string
}

type Dog struct {
    name string
}

func (c *Cat) Talk(words string) {
    fmt.Printf("猫 " + c.name + " 在这里说:" + words + "\n")
}

func (d *Dog) Talk(words string) {
    fmt.Printf("狗 " + d.name + " 在这里说:" + words + "\n")
}

func main() {
    var t1, t2 Talker

    t1 = &Cat{"Kit"}
    t2 = &Dog{"Doug"}

    t1.Talk("喵喵")
    t2.Talk("汪汪")
}

这段代码定义了一个Talker接口,该接口有一个Talk方法。然后定义了CatDog两个结构体,并分别实现了Talk方法。在main函数中,创建了一个Talker类型的变量t1t2,分别指向CatDog的实例。最后调用Talk方法分别输出了猫和狗的声音。

英文:

I once found this example of how to do polymorphism in Go:

http://play.golang.org/p/6Ip9scm4c3

package main

import "fmt"

type Talker interface {
        Talk(words string)
}

type Cat struct {
        name string
}

type Dog struct {
        name string
}

func (c *Cat) Talk(words string) {
        fmt.Printf("Cat " + c.name + " here: " + words + "\n")
}

func (d *Dog) Talk(words string) {
        fmt.Printf("Dog " + d.name + " here: " + words + "\n")
}

func main() {
        var t1, t2 Talker

        t1 = &Cat{"Kit"}
        t2 = &Dog{"Doug"}

        t1.Talk("meow")
        t2.Talk("woof")
}

答案3

得分: 2

回答标题中的问题:
Go语言不使用类,但提供了许多相同的功能:

  • 通过方法进行消息传递
  • 通过嵌入实现自动消息委托
  • 通过接口实现多态性
  • 通过导出实现命名空间

来源:http://nathany.com/good/

至于你提供的代码的解决方案,我会留给更有经验的Gopher来完成。

英文:

To answer the question the in the title to post:

> Go does not use classes, but provides many of the same features:
>
> * message passing with methods
> * automatic message delegation via embedding
> * polymorphism via interfaces
> * namespacing via exports

From: http://nathany.com/good/

Solving the code you supplied, I will leave to some more learned Gopher

答案4

得分: 2

AD HOC多态性

Ad hoc多态性是一种用于静态类型语言的多态性实现的通用方式。Go语言中的多态性是一种接近Bjarne Stroustrup定义的ad hoc多态性:

多态性 - 为不同类型的实体提供单一接口。

接口

Go语言的interface是一种非常强大的工具,专门用于多态性的实现。接口是一种类型抽象(方法集),它提供了一种指定对象行为的方式:如果某个对象可以做到这一点,那么它就可以在这里使用。回到Stroustrup的多态性定义:如果对象实现了接口,那么可以将不同类型的对象作为共同接口的类型使用。

带有示例的Playground。

参数多态性

维基百科:

函数或数据类型可以以通用方式编写,以便在不依赖于其类型的情况下对其进行相同处理。

这种多态性对于像Python或Ruby这样的动态类型语言来说更加常见,但Go也实现了它!Go使用空接口interface{}来实现这个目的。

类型interface{}

来自Go之旅:

指定零个方法的接口类型被称为空接口:

interface{}
空接口可以保存任意类型的值。每种类型至少实现了零个方法。

空接口被用于处理未知类型的值的代码。例如,fmt.Print接受任意数量的interface{}类型的参数。

并且可以使用类型断言获取对象的特定类型。

再次来自Go之旅:

类型断言提供对接口值的底层具体值的访问。

t := i.(T)

此语句断言接口值i保存了具体类型T,并将底层T值分配给变量t。

这就是具有静态鸭子类型的参数多态性。

英文:

###AD HOC polymophism

Ad hoc polymorphism is a general way of polymorphism implementation for statically typed languages. Polymorphism in Go is ad hoc polymorphism which is very close to Bjarne's Stroustrup definition:

> Polymorphism – providing a single interface to entities of different types.

Interfaces

Go interface is really powerful tool designed specially for polymorphism implementation. Interface is a type abstraction (sets of methods) which provides a way to specify the behavior of an object: if something can do this, then it can be used here. Back to Straustrup's polymorphism definition: it is possible to use objects of different types as a type of a common interface if they implement the interface.

Playground with an example.

Parametric polymorphism

Wiki:
> A function or a data type can be written generically so that it can handle values identically without depending on their type.

This kind of polymorphism is more regular for dynamically typed languages like Python or Ruby but Go implements it too! Go uses type empty interface interface{} for this purpose.

Type interface{}

From Tour Of Go:

> The interface type that specifies zero methods is known as the empty interface:

>interface{}
An empty interface may hold values of any type. Every type implements at least zero methods.

>Empty interfaces are used by code that handles values of unknown type. For example, fmt.Print takes any number of arguments of type interface{}.

And it is possible to get particular type of an object with type assertion.

And again Tour Of Go:

> A type assertion provides access to an interface value's underlying concrete value.

t := i.(T)

> This statement asserts that the interface value i holds the concrete type T and assigns the underlying T value to the variable t.

There we have parametric polymorphism with static duck typing.

huangapple
  • 本文由 发表于 2014年4月22日 14:07:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/23211648.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定