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

I have multiple types and I want to pass around data of those types, like store them in a variable and pass them to functions:

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

I would like cook() to accept Pizza and Steak for food but not Car.

Since interfaces are defined by their methods and my types don't share any common methods, I can't let them "implement" an interface.

I could also introduce an identifying receiver function, like this:

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

Is that common/idiomatic?

Go provides interfaces to support your requirements. As an example, you can have an interface called Food:

type Food interface {
    Cook()
}

Now let Pizza and Steak satisfy this interface:

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

You can now have a CookFood method that can accept both Pizza and Steak:

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

You can call this like:

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

    CookFood(favoriteFood)
}

Calling CookFood with Car (which does not implement Cook method) would make compiler throw an error, providing proper type safety.

Ok, I changed your code making use of interface: here

The interface part:

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

The whole point (well, maybe not whole but very closely) of interface is to hide implentation details. For example, a Pizza's size, name or other attribute are such details, the function cook care not about them. Nor does it care about whether a steak is over-done, nor whether you are cooking a dragon, as a dragon has a method CookedInfo. And each food implents its own method to provide info of being cooked, used by Cook. That is it. It prevents you to write an infinate list of testing types (which even become impossible when the function is being exported as in a lib) and simplify your logic.

I’ve slightly modified previous example - https://play.golang.org/p/uN1m7pNZbsv

You may try to use embedding and embed interface Food into a concrete structures Pizza and Steak but not car.

type Food interface {
    Cook()
}

type Pizza struct {
    Food
    Diameter int
}

func Cook(food Food) {
   ...
}

This way only structs matching Food will be accepted.

But do not forget Go is duck-typed language, so if you suddenly implement method Cook on Chair you may start cooking it ) However it doesn’t embed Food explicitly.