切片(从有限数量的接口中选择一个)

How can I make the RemoveDead function accept other slices of interfaces (or maybe even slices of struct pointers) that implement Liver with little impact on performance?

It seems to me that the function would have to take an interface{} as argument and do runtime conversions, but I'm not sure how to do the conversions. I would also guess that doing x.(Liver) is a lot slower than Liver(x), because the latter is a compile time conversion.

Is the best solution to copy-paste the function and change the argument and return type in each copy? Only three or four copies would be needed, but it would still feel like a very clumsy solution.

type Updater interface {
    Liver
    Update() bool
}

type Liver interface {
    Alive() bool
}

func RemoveDead(all []Updater) []Updater {
    for i := len(all) - 1; i >= 0; i-- {
        if Liver(all[i]).Alive() == false {
            all[i] = all[len(all)-1]
            all = all[:len(all)-1]
        }
    }
    return all
}

As you mentioned, a slice of type []Updater cannot be turned to a []Liver with a simple type assertion; their type are not interfaces, but slices of interfaces. For the same reason is it not possible to pass a []Updater to a function wanting an []interface{} as parameter.

However, you can do what you desire using the reflect package. Reflection is useful but will come at a cost on performance. If you consider the cost to high, then you will probably have to use the copy-paste solution.

The code below can surely be improved, but it shows how to solve the problem with reflection, and it might be useful when making a benchmark. Currently it regards any even U value as Alive:

package main

import (
    "fmt"
    "reflect"
)

type Updater interface {
    Alive() bool
    Update() bool
}

type Liver interface {
    Alive() bool
}

type U int
func (u U) Alive() bool  { return u % 2 == 0 }

func RemoveDead(all interface{}) interface{} {
    v := reflect.ValueOf(all)
    if v.Kind() != reflect.Slice {
        panic("RemoveDead requires a slice")
    }
    for i := v.Len() - 1; i >= 0; i-- {
        l := v.Index(i)
        if l.Interface().(Liver).Alive() == false {
            l.Set(v.Index(v.Len()-1))
            v = v.Slice(0, v.Len()-1)
        }
    }
    return v.Interface()
}

func main() {
    u := []U{1,4,7,2,12}
    fmt.Println("Before: ", u)
    u  = RemoveDead(u).([]U)
    fmt.Println("After: ", u)
}

Output:

Before:  [1 4 7 2 12]
After:  [2 4 12]

Playground

You could define third interface:

type UpdaterLiver interface {
    Updater
    Liver
}

then change definition of RemoveDead to be

func RemoveDead(all []UpdaterLiver) []UpdaterLiver