Is it possible to have Optional methods inside the interface in golang?

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

Is it possible to have Optional methods inside the interface in golang?

问题

我想为接口创建可选的perim方法。这可能吗?比如说,我不想为三角形创建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("矩形的面积:", g.area())
		fmt.Println("矩形的周长:", g.perim())
	case circle:
		fmt.Printf("圆的面积: %.2f\n", g.area())
		fmt.Printf("圆的周长: %.2f\n", g.perim())
	case square:
		fmt.Printf("正方形的面积: %.2f\n", g.area())
		fmt.Printf("正方形的周长: %.2f\n", g.perim())
	case triangle:
		fmt.Printf("三角形的面积: %.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)
}
英文:

I want to create optional perim mehtod for interface. Is it possible?Like I don't want to create perim method for triangle but its giving me error that one method is missing. Is it possible to have optional method in interface?

Please tell me its alternative or some solution.

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)
}

答案1

得分: 3

规范不允许在接口类型中将方法标记为可选的。

请注意,你的实现可以提供其他方法,而不仅仅是接口中定义的方法。可以使用类型断言来检查值的具体类型是否具有“额外”方法,方法是检查它们是否实现了具有这些额外方法的接口类型。

在这个例子中,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))
}

它的输出结果是:

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 上尝试一下。

英文:

The spec does not allow "marking" methods optional in interface types.

Note that your implementations may provide other methods, not just the methods that are part of the interface you want to implement. Type assertion may be used to check if the concrete type of a value has "additional" methods, by checking if they implement an interface type having those additional methods.

In this example FooImpl has only method One(), but Foo2Impl has methods One() and 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))
}

Its output (try it on the Go Playground):

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

You can of course create an interface type with those additional methods:

type Bar interface {
Two()
}

And then checking it:

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)
}

Try this one on the Go Playground.

答案2

得分: 1

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

func measure(g interface{}) {
    fmt.Println(g)
    switch v := g.(type) {
    case rect:
        fmt.Println("矩形面积:", v.area())
        fmt.Println("矩形周长:", v.perim())
    case circle:
        fmt.Printf("圆的面积:%.2f\n", v.area())
        fmt.Printf("圆的周长:%.2f\n", v.perim())
    case square:
        fmt.Printf("正方形的面积:%.2f\n", v.area())
        fmt.Printf("正方形的周长:%.2f\n", v.perim())
    case triangle:
        fmt.Printf("三角形的面积:%.2f\n", v.area())
    }
}

Go Playground

这是否是适当的设计(面向对象编程的人可能会不同意),取决于上下文。

英文:

Since you're already using type-switch statements, your argument g can be an empty interface as well:

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)

Whether it's appropriate design (OOP people would disagree), depends on the context.

答案3

得分: -1

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

然而,你可以使用多个接口。例如,在net/http包中就使用了这种方式,其中ResponseWriter可能是一个Pusher,在这种情况下,Pusher描述了“可选”的Push方法,可以通过类型断言来访问,如下所示:

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

Interfaces cannot have optional methods by definition; there's no way for an optional method to work. If you have a value of an interface type, you can call any method defined on that interface on that value. If a method were optional, you couldn't assume it was available, so you couldn't call it, so there would be no point having it in the interface.

You can, however, just use multiple interfaces. This is used in the net/http package, for example, where a ResponseWriter may or may not be a Pusher; in this case, Pusher describes the "optional" Push method, which can be accessed by type assertion like so:

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

huangapple
  • 本文由 发表于 2021年6月3日 22:34:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/67823459.html
匿名

发表评论

匿名网友

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

确定