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

问题描述 投票:-1回答:3

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

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()接受PizzaSteakfood而不是Car

由于接口是由它们的方法定义的,并且我的类型不共享任何常用方法,所以我不能让它们“实现”接口。

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

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

这是常见/惯用吗?

go
3个回答
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会使编译器抛出错误,提供适当的类型安全性。


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使用的烹饪信息。这就对了。它会阻止您编写一个测试类型的无限列表(当在函数库中导出函数时甚至变得不可能)并简化您的逻辑。


0
投票

我稍微修改了前面的例子 - https://play.golang.org/p/uN1m7pNZbsv

您可以尝试使用嵌入和嵌入接口Food到混凝土结构PizzaSteak而不是汽车。

type Food interface {
    Cook()
}

type Pizza struct {
    Food
    Diameter int
}

func Cook(food Food) {
   ...
}

这种方式只接受匹配Food的结构。

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

© www.soinside.com 2019 - 2024. All rights reserved.