【问题标题】:Is it possible to have Optional methods inside the interface in golang?golang的接口内是否可以有可选方法?
【发布时间】:2021-08-21 16:40:49
【问题描述】:

我想为接口创建可选的 perim mehtod。有可能吗?就像我不想为三角形创建 perim 方法,但它给了我一个错误,即缺少一种方法。接口中是否可以有可选方法?

请告诉我它的替代方案或解决方案。

type geometry interface {
    area() float64
    perim() float64
}

type rect struct {
    width, height float64
}

type triangle struct {
    base, height float64
}

type circle struct {
    radius float64
}

type square struct {
    side float64
}

func (r rect) area() float64 {
    return r.width * r.height
}

func (r rect) perim() float64 {
    return 2*r.width + 2*r.height
}

func (c circle) area() float64 {
    return math.Pi * c.radius * c.radius
}

func (c circle) perim() float64 {
    return 2 * math.Pi * c.radius
}

func (t triangle) area() float64 {
    return 1 / 2 * t.base * t.height
}

func measure(g geometry) {
    fmt.Println(g)
    switch g.(type) {
    case rect:
        fmt.Println("Rectangles area :", g.area())
        fmt.Println("Rectangle perimeter: ", g.perim())
    case circle:
        fmt.Printf("Circles Area: %.2f\n", g.area())
        fmt.Printf("Circles Perimeter: %.2f\n", g.perim())
    case square:
        fmt.Printf("Area of square: %.2f\n", g.area())
        fmt.Printf("Perimeters of area: %.2f\n", g.perim())
    case triangle:
        fmt.Printf("Area of  triangle: %.2f\n", g.area())
    }
}

func main() {
    r := rect{width: 3, height: 4}
    c := circle{radius: 5}
    s := square{side: 7}
    t := triangle{base: 3, height: 4}
    measure(r)
    measure(c)
    measure(s)
    measure(t)
}

【问题讨论】:

  • 是的 g 是接口所以我可以使用空接口概念吗?

标签: go methods interface


【解决方案1】:

规范不允许在interface 类型中使用可选的“标记”方法。

请注意,您的实现可能会提供其他方法,而不仅仅是您要实现的接口中的方法。 Type assertion 可用于检查值的具体类型是否具有“附加”方法,方法是检查它们是否实现了具有这些附加方法的接口类型。

在这个例子中FooImpl只有方法One(),但是Foo2Impl有方法One()Two()

type Foo interface {
    One()
}

type FooImpl int

func (fi FooImpl) One() {}

type Foo2Impl int

func (fi Foo2Impl) One() {}
func (fi Foo2Impl) Two() {}

func check(f Foo) {
    if ft, ok := f.(interface{ Two() }); ok {
        fmt.Printf("%T(%v) has method Two()\n", f, f)
        ft.Two() // You can call it
    } else {
        fmt.Printf("%T(%v) doesn't have method Two()\n", f, f)
    }
}

func main() {
    check(FooImpl(1))
    check(Foo2Impl(2))
}

它的输出(在Go Playground上试试):

main.FooImpl(1) doesn't have method Two()
main.Foo2Impl(2) has method Two()

您当然可以使用这些附加方法创建接口类型:

type Bar interface {
    Two()
}

然后检查它:

if ft, ok := f.(Bar); ok {
    fmt.Printf("%T(%v) has method Two()\n", f, f)
    ft.Two() // You can call it
} else {
    fmt.Printf("%T(%v) doesn't have method Two()\n", f, f)
}

Go Playground 上试试这个。

【讨论】:

    【解决方案2】:

    由于您已经在使用type-switch statements,您的参数g 也可以是一个空接口:

    func measure(g interface{}) {
        fmt.Println(g)
        switch v := g.(type) {
        case rect:
            fmt.Println("Rectangles area :", v.area())
            fmt.Println("Rectangle perimeter: ", v.perim())
        case circle:
            fmt.Printf("Circles Area: %.2f\n", v.area())
            fmt.Printf("Circles Perimeter: %.2f\n", v.perim())
        case square:
            fmt.Printf("Area of square: %.2f\n", v.area())
            fmt.Printf("Perimeters of area: %.2f\n", v.perim())
        case triangle:
            fmt.Printf("Area of  triangle: %.2f\n", v.area())
        }
    }
    

    (Go Playground)

    是否合适的设计(OOP 的人会不同意)取决于上下文。

    【讨论】:

    • 是的,但我是新手,正在尝试使用 golang。
    【解决方案3】:

    根据定义,接口不能有可选方法;可选方法无法正常工作。如果你有一个接口类型的值,你可以在那个值上调用在该接口上定义的任何方法。如果一个方法是可选的,你不能假设它是可用的,所以你不能调用它,所以在接口中没有任何意义。

    但是,您可以只使用多个接口。这用于net/http 包中,例如,ResponseWriter 可能是也可能不是Pusher;在这种情况下,Pusher 描述了“可选”Push 方法,可以通过类型断言访问,如下所示:

    if ok,pusher := resp.(Pusher); ok {
        pusher.Push(...)
    }
    

    【讨论】:

      猜你喜欢
      • 2016-02-26
      • 2023-04-10
      • 2015-08-21
      • 1970-01-01
      • 1970-01-01
      • 2010-12-24
      • 1970-01-01
      • 2021-11-20
      • 2010-10-30
      相关资源
      最近更新 更多