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

Interface 切片(从有限数量的接口中选择一个),interface,go,slice,Interface,Go,Slice,如何使RemoveDead函数接受实现Liver而对性能影响不大的其他接口片(甚至可能是结构指针片) 在我看来,函数必须以接口{}作为参数并进行运行时转换,但我不确定如何进行转换。我还想做x.(Liver)比Liver(x)慢得多,因为后者是编译时转换 复制粘贴函数并更改每个副本中的参数和返回类型的最佳解决方案是什么?只需要三到四份拷贝,但这仍然是一个非常笨拙的解决方案 type Updater interface { Liver Update() bool } type Li

如何使
RemoveDead
函数接受实现
Liver
而对性能影响不大的其他接口片(甚至可能是结构指针片)

在我看来,函数必须以
接口{}
作为参数并进行运行时转换,但我不确定如何进行转换。我还想做
x.(Liver)
Liver(x)
慢得多,因为后者是编译时转换

复制粘贴函数并更改每个副本中的参数和返回类型的最佳解决方案是什么?只需要三到四份拷贝,但这仍然是一个非常笨拙的解决方案

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
}

您可以定义第三个接口:

type UpdaterLiver interface {
    Updater
    Liver
}
然后将
RemoveDead
的定义更改为

func RemoveDead(all []UpdaterLiver) []UpdaterLiver

您可以定义第三个接口:

type UpdaterLiver interface {
    Updater
    Liver
}
然后将
RemoveDead
的定义更改为

func RemoveDead(all []UpdaterLiver) []UpdaterLiver

正如您所提到的,不能通过简单的类型断言将
[]Updater
类型的片段转换为
[]Liver
;它们的类型不是接口,而是接口的片段。出于同样的原因,不可能将
[]更新程序
传递给需要
[]接口{}
作为参数的函数

但是,您可以使用
reflect
软件包执行所需操作。反射是有用的,但会以性能为代价。如果你认为成本高,那么你可能需要使用复制粘贴解决方案。
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
}
下面的代码当然可以改进,但它展示了如何使用反射解决问题,并且在制作基准时可能会很有用。目前,它认为任何偶数U值都是活动的:

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)
}
输出:

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

正如您所提到的,不能通过简单的类型断言将类型为
[]Updater
的片段转换为
[]Liver
;它们的类型不是接口,而是接口的片段。出于同样的原因,不可能将
[]更新程序
传递给需要
[]接口{}
作为参数的函数

但是,您可以使用
reflect
软件包执行所需操作。反射是有用的,但会以性能为代价。如果你认为成本高,那么你可能需要使用复制粘贴解决方案。
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
}
下面的代码当然可以改进,但它展示了如何使用反射解决问题,并且在制作基准时可能会很有用。目前,它认为任何偶数U值都是活动的:

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)
}
输出:

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

这实际上没有帮助,因为各种切片类型都不可互换:这实际上没有帮助,因为各种切片类型都不可互换:您可能有兴趣阅读这个SO问题:您可能有兴趣阅读这个SO问题: