可以存储多个类型但没有共享功能的变量

时间:2018-01-04 10:31:18

标签: go

我有多种类型,我想传递这些类型的数据,比如将它们存储在变量中并将它们传递给函数:

type Pizza struct {
    Toppings []string
    Diameter int
}
type Steak struct {
    Weight   float64
    Doneness string
}
type Car struct {
    Speed int
}
type Chair struct {
}

func main() {
    var favoriteFood interface{}

    favoriteFood = Pizza{
        Diameter: 20,
    }

    cook(favoriteFood, Chair{})
}

func cook(food interface{}, vehicle interface{}) {
    fmt.Print("Cooking ")

    if pizza, ok := food.(Pizza); ok {
        fmt.Println("a " + strconv.Itoa(pizza.Diameter) + " cm pizza")
    }
    if steak, ok := food.(Steak); ok {
        fmt.Println("a " + steak.Doneness + " steak")
    }

    if car, ok := vehicle.(Car); ok {
        fmt.Print(" in a car at " + strconv.Itoa(car.Speed) + " km/h")
    }
    if _, ok := vehicle.(Chair); ok {
        fmt.Print(" on a chair")
    }
}

Full example

我希望cook()接受PizzaSteak接受food但不接受Car

由于接口是由他们的方法定义的,而我的类型不共享任何常用方法,我不能让他们实现"界面。

我还可以介绍一个识别接收器功能,如下所示:

type Food interface {
    IsFood() bool
}
func (f *Pizza) IsFood() bool { return true }
func (f *Steak) IsFood() bool { return true }

这是常见/惯用吗?

3 个答案:

答案 0 :(得分:0)

Go提供了支持您需求的界面。例如,您可以使用名为Food的接口:

type Food interface {
    Cook()
}

现在让PizzaSteak满足此界面:

func (p *Pizza) Cook() {
    // use Pizza's fields
    // ...
}

您现在可以使用CookFood方法同时接受PizzaSteak

func CookFood(f Food) {
    // ...
    f.Cook()
    // ...
}

你可以这样称呼:

func main() {
    var favoriteFood = Pizza{
        Diameter: 20,
    }

    CookFood(favoriteFood)
}

使用CookFood(未实现Car方法)调用Cook会使编译器抛出错误,从而提供正确的类型安全性。

答案 1 :(得分:0)

好的,我使用界面更改了您的代码:here

界面部分:

type Food interface {
    CookedInfo() string 
}

func (p Pizza) CookedInfo() string {
    return "a " + strconv.Itoa(p.Diameter) + " cm pizza"
}

func (s Steak) CookedInfo() string {
    return "a" + s.Doneness + " steak"
}

type Location interface { //chair is hardly a vehicle
    Where() string
}

func (c Chair) Where() string {
    return "on a chair"
}

func (c Car) Where() string {
    return "in a car at " + strconv.Itoa(c.Speed) + " km/h"
}

interface的重点(好吧,可能不完整但非常密切)是隐藏实施细节。例如,Pizza的大小,名称或其他属性就是这样的细节,函数cook不关心它们。它也不关心牛排是否过度完成,也不关心你是否正在烹饪龙,因为龙有一种方法CookedInfo。每种食物都有自己的方法来提供被Cook使用的烹饪信息。这就对了。它会阻止您编写一个无限的测试类型列表(当函数在lib中导出时甚至变得不可能)并简化您的逻辑。

答案 2 :(得分:0)

我稍微修改过上一个示例 - https://play.golang.org/p/uN1m7pNZbsv

您可以尝试将嵌入和嵌入接口SOL_SOCKET/SO_PRIORITY用于具体结构FoodPizza,但不能使用car。

Steak

这种方式只接受匹配type Food interface { Cook() } type Pizza struct { Food Diameter int } func Cook(food Food) { ... } 的结构。

但是不要忘记Go是鸭式语言,所以如果你突然在Food上实现方法Cook,你可以start cooking it) 但是它没有明确嵌入Chair