我有多种类型,我想传递这些类型的数据,比如将它们存储在变量中并将它们传递给函数:
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")
}
}
我希望cook()
接受Pizza
和Steak
为food
而不是Car
。
由于接口是由它们的方法定义的,并且我的类型不共享任何常用方法,所以我不能让它们“实现”接口。
我还可以介绍一个识别接收器功能,如下所示:
type Food interface {
IsFood() bool
}
func (f *Pizza) IsFood() bool { return true }
func (f *Steak) IsFood() bool { return true }
这是常见/惯用吗?
Go提供了支持您需求的接口。例如,您可以使用名为Food
的界面:
type Food interface {
Cook()
}
现在让Pizza
和Steak
满足这个界面:
func (p *Pizza) Cook() {
// use Pizza's fields
// ...
}
你现在可以有一个CookFood
方法,可以接受Pizza
和Steak
:
func CookFood(f Food) {
// ...
f.Cook()
// ...
}
您可以这样称呼:
func main() {
var favoriteFood = Pizza{
Diameter: 20,
}
CookFood(favoriteFood)
}
用CookFood
(没有实现Car
方法)调用Cook
会使编译器抛出错误,提供适当的类型安全性。
好的,我使用界面改变了你的代码: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
使用的烹饪信息。这就对了。它会阻止您编写一个测试类型的无限列表(当在函数库中导出函数时甚至变得不可能)并简化您的逻辑。
我稍微修改了前面的例子 - https://play.golang.org/p/uN1m7pNZbsv
您可以尝试使用嵌入和嵌入接口Food
到混凝土结构Pizza
和Steak
而不是汽车。
type Food interface {
Cook()
}
type Pizza struct {
Food
Diameter int
}
func Cook(food Food) {
...
}
这种方式只接受匹配Food
的结构。
但是不要忘记Go是鸭型语言,所以如果你突然在Cook
上实现方法Chair
你可能start cooking it)但是它没有明确地嵌入Food
。