简体   繁体   中英

How can I loop over values of different struct types and call the same method on each?

package main

import (
    "fmt"
    "math"
)

type Rect struct {
    width  float64
    height float64
}

type Circle struct {
    radius float64
}

func (r Rect) Area() float64 {
    return r.width * r.height
}

func (c Circle) Area() float64 {
    return math.Pi * c.radius * c.radius
}

func main() {
    rect := Rect{5.0, 4.0}
    cir := Circle{5.0}
    fmt.Printf("Area of rectangle rect = %0.2f\n", rect.Area())
    fmt.Printf("Area of circle cir = %0.2f\n", cir.Area())
}

This basic common example of the struct. But my question is how can I run struct's method with the same name when more than one.

In this example, there is 2 struct. But if there 50 structs (Circle, Rect, Foo, Bar ....) and all of them had a method with the same name (Area) . How I run these methods in a loop concurrently and dynamic?

Maybe I need an interface some how. I don't know.

Use a slice of interface with the Area method:

shapes := []interface{ Area() float64 }{Rect{5.0, 4.0}, Circle{5.0}}
for _, shape := range shapes {
    fmt.Printf("Area of %T = %0.2f\n", shape, shape.Area())
}

Run it on the GoLang PlayGround

This is really two questions in one: how to create the interface, and how to run something concurrently.

Defining the interface is easy:

type Shape interface {
    Area() float64
}

Because of the magic of Go, every type for which an Area() float64 function is defined automatically implements this interface.

Thanks to this interface, we can put multiple shapes into a slice:

    shapes := []Shape{
        Rect{5.0, 4.0},
        Circle{5.0},
    }

Looping over this is easy:

    for _, shape := range shapes {
        // Do something with shape
    }

Printing the area concurrently is really not something you want to do. It gives unpredictable output, where multiple lines may be mixed together. But let's suppose we compute the areas concurrently, then print them all at the end:

    areas := make(chan float64)
    for _, shape := range shapes {
        currentShape := shape
        go func() { areas <- currentShape.Area() }()
    }
    for i := 0; i < len(shapes); i++ {
        fmt.Printf("Area of shape = %0.2f\n", <-areas)
    }

Note how we have to capture the currentShape in a local variable inside the loop, to avoid it changing value inside the goroutine before the goroutine has a chance to run.

Also note how we don't use for area := range areas to consume the channel. That would cause a deadlock, because the channel is not closed after all the areas have been written to it. There are other (and maybe more elegant) ways to solve this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM