接口实现中的非接口方法

时间:2018-08-01 00:41:05

标签: oop go

我有一个定义方法的接口。我有一个实现此接口的结构。在其中,我已经从该接口实现了方法,并且还定义了其他方法。

例如:

package main

import (
    "fmt"
)   

type Animal interface {
    MakeNoise()
}

type Dog struct {
    color string
}

/* Interface implementation */

func (d *Dog) MakeNoise() {
    fmt.Println("Bark!")
}

/* End Interface implementation */

func (d *Dog) WagTail() {
    fmt.Println(d.color + " dog: Wag wag")
}

func NewDog(color string) Animal {
    return &Dog{color}
}

func main() {
    dog := NewDog("Brown")
    dog.MakeNoise()
    dog.WagTail()

}

在操场上:https://play.golang.org/p/B1GgoNToNl_l

在这里,WagTail()不是Animal接口的一部分,但属于Dog结构。运行此代码会出现错误

  

dog.WagTail未定义(动物类型没有字段或方法WagTail)。

有没有办法让结构坚持接口并定义其自己的方法?

4 个答案:

答案 0 :(得分:2)

这可能会对您有所帮助。

d := dog.(*Dog)
d.WagTail()

在操场上:https://play.golang.org/p/KlNqpmvFTJi

答案 1 :(得分:2)

您绝对可以做到,其中一种方法是使用类型声明,如另一答案here所示。否则,@ Himanshu here的回答很好地描述了这种情况。

我想添加到讨论中以进一步描述您的方式

  

可以有一个结构坚持一个接口,也可以定义它自己的方法

MakeDog方法返回动物,并且出于多种原因,您可以考虑直接返回Dog(或任何具体类型)。

之所以提出这一点,是因为我刚开始使用Go编程时有人告诉我有关创建方法的事情:

  

接受接口并返回具体类型(例如Struct)

接口可以接受任何具体类型。这就是为什么当您不知道要传递给函数的参数类型时使用它们的原因。

我用以下字词在Google搜索中发现了不少文章

  

golang accept接口,返回结构

例如:https://mycodesmells.com/post/accept-interfaces-return-struct-in-gohttp://idiomaticgo.com/post/best-practice/accept-interfaces-return-structs/

我整理了一个有关您问题中概念的演示,以尝试清楚地描述接口方法以及特定类型的方法和属性

取自this snippet on Playground

package main

import (
    "fmt"
)

type Animal interface {
    MakeNoise() string
}

// printNoise accepts any animal and prints it's noise
func printNoise(a Animal) {
    fmt.Println(a.MakeNoise())
}

type pet struct {
    nLegs int
    color string
}

// describe is available to all types of Pet, but not for an animal
func (p pet) describe() string {
    return fmt.Sprintf(`My colour is "%s", and I have "%d" legs`, p.color, p.nLegs)
}

type Dog struct {
    pet
    favouriteToy string
}

// MakeNoise implements the Animal interface for type Dog
func (Dog) MakeNoise() string {
    return "Bark!"
}

// WagTail is something only a Dog can do
func (d Dog) WagTail() {
    fmt.Println("I am a dog,", d.pet.describe(), ": Wags Tail")
}

type Cat struct {
    pet
    favouriteSleepingPlace string
}

// MakeNoise implements the Animal interface for type Cat
func (Cat) MakeNoise() string {
    return "Meow!"
}

// ArchBack is something only a Cat can do
func (c Cat) ArchBack() {
    fmt.Println("I am a cat,", c.pet.describe(), ": Arches Back")
}

type Bird struct {
    pet
    favoritePerch string
}

// MakeNoise implements the Animal interface for type Cat
func (Bird) MakeNoise() string {
    return "Tweet!"
}

// Hop is something only a Bird can do
func (c Bird) Hop() {
    fmt.Println("I am a bird,", c.pet.describe(), ": Hops to a different perch")
}

func main() {
    dog := Dog{
        pet:          pet{nLegs: 4, color: "Brown"},
        favouriteToy: "Ball",
    }
    printNoise(dog)
    dog.WagTail()

    cat := Cat{
        pet: pet{nLegs: 4, color: "Tabby"},
        favouriteSleepingPlace: "Sofa",
    }
    printNoise(cat)
    cat.ArchBack()

    bird := Bird{
        pet:           pet{nLegs: 2, color: "Rainbow"},
        favoritePerch: "Back of Cage",
    }

    printNoise(bird)
    bird.Hop()

}

答案 2 :(得分:2)

错误描述了全部内容

  

dog.WagTail未定义(动物类型没有字段或方法WagTail)

要实现接口,您应该实现接口中定义的所有方法。

dog := NewDog("Brown")
dog.MakeNoise()
dog.WagTail()

现在NewDog返回Animal接口,其中包含MakeNoise方法,但不包含WagTail

管理需求的唯一方法是创建结构类型为Dog的变量,然后可以调用将Dog作为接收者的任何方法。

d := &Dog{"Brown"}
d.WagTail()

或者您可以从Dog方法返回指向NewDog结构的指针,就像在注释中提到的代码中那样:

func NewDog(color string) *Dog {
    return &Dog{color}
}

但是,如果未在接口中定义该方法,则无法使用struct作为方法接收者来实现它。

Golang提供了一种方法:

  

您可以要求编译器检查类型T是否实现了   通过尝试使用T的零值进行赋值来接口I   适当的指向T的指针

type T struct{}
var _ I = T{}       // Verify that T implements I.
var _ I = (*T)(nil) // Verify that *T implements I.

如果T(或* T,相应地)没有实现I,则错误将在编译时捕获。

  

如果您希望某个接口的用户明确声明他们   实施它,您可以将带有描述性名称的方法添加到   接口的方法集。例如:

type Fooer interface {
    Foo()
    ImplementsFooer()
}

然后,类型必须将ImplementsFooer方法实现为Fooer,清楚地记录事实并在godoc的输出中宣布该事实。

type Bar struct{}
func (b Bar) ImplementsFooer() {}
func (b Bar) Foo() {}
  

大多数代码未使用此类约束,因为它们限制了   界面想法的实用程序。但是有时候,它们对于   解决相似界面之间的歧义。

答案 3 :(得分:1)

是的,您可以运行不属于接口的方法。代码中存在两个问题,无法正常运行。

  1. 函数NewDog返回类型Animal。 WagTale方法附加在Dog not Animal上,这导致了错误。返回类型已更改为Dog。
  2. 此代码中不需要指针,指针已被删除。

进行这些调整后,代码将正常运行,并且所有方法均按预期执行。

Go游乐场链接:https://play.golang.org/p/LYZJiQND7WW

package main

import (
    "fmt"
)


type Animal interface {
    MakeNoise()
}

type Dog struct {
    color string
}

/* Interface implementation */

func (d Dog) MakeNoise() {
    fmt.Println("Bark!")
}

/* End Interface implementation */

func (d Dog) WagTail() {
    fmt.Println(d.color + " dog: Wag wag")
}

func NewDog(color string) Dog {
    return Dog{color}
}

func main() {
    dog := NewDog("Brown")
    dog.MakeNoise()
    dog.WagTail()
    
}