从任意接口列表中满足哪些接口?

huangapple go评论78阅读模式
英文:

Which interfaces satisfied from list of arbitrary interfaces?

问题

有一种方法可以从任意接口列表中确定一个具体类型实现了哪些接口吗?我知道可以使用类型切换,但我想知道所有满足的接口。

例如,给定以下代码:

type Mover interface  { Move() }
type Talker interface { Talk() }
type Flyer interface  { Fly() }

type Person struct{}
func (a *Person) Move() {fmt.Println("Moving...") }
func (a *Person) Talk() {fmt.Println("Talking...") }

我可以手动测试每个接口,如下所示:

func testInterfaces(entity interface{}) {

	_, ok := entity.(Mover)
	if ok {
		fmt.Println("mover")
	}
	_, ok := entity.(Talker)
	if ok {
		fmt.Println("talker")
	}
	_, ok := entity.(Flyer)
	if ok {
		fmt.Println("flyer")
	}
}

对于一个Person值,将打印出"mover"和"talker"。然而,我更希望有一个像下面这样的函数(非工作中的函数):

func testInterfaces2(entity interface{}, interfaceList type??) {
	for _, inter := range interfaceList {
		val, ok := entity.(inter)
		if ok {
			// 对val进行一些操作
		}
	}
}

有没有办法实现类似这个伪函数的功能,也许通过reflect包或其他方式?

英文:

Is there a way I can determine which interfaces a concrete type implements from an
arbitrary list of interfaces? I'm aware of a type switch, but I'd like to know all satisfied
interfaces.

For example, given:

type Mover interface  { Move() }
type Talker interface { Talk() }
type Flyer interface  { Fly() }

type Person struct{}
func (a *Person) Move() {fmt.Println("Moving...") }
func (a *Person) Talk() {fmt.Println("Talking...") }

I can manually test each interface as follows:

func testInterfaces(entity interface{}) {

	_, ok := entity.(Mover)
	if ok {
		fmt.Println("mover")
	}
	_, ok := entity.(Talker)
	if ok {
		fmt.Println("talker")
	}
	_, ok := entity.(Flyer)
	if ok {
		fmt.Println("flyer")
	}
}

For a Person value, "mover", and "talker" will print. However, I'd rather have a function like this (non-working) one:

func testInterfaces2(entity interface{}, interfaceList type??) {
	for _, inter := range interfaceList {
		val, ok := entity.(inter)
		if ok {
			// do something with val
		}
	}
}

Is there a way I can achieve something like this pseudo function, maybe through the reflect package or some other means?

答案1

得分: 3

你可以使用这个链接来获取接口类型的切片。

然后,你可以像这里一样检查你的值的Type是否实现了该接口:

interfaces := []reflect.Type{reflect.TypeOf((*Mover)(nil)).Elem(), 
    reflect.TypeOf((*Talker)(nil)).Elem(), 
    reflect.TypeOf((*Flyer)(nil)).Elem()}
p := &Person{}
t := reflect.TypeOf(p)
name := t.Elem().Name()
for _, interf := range interfaces {
    if t.Implements(interf) {
        fmt.Printf("%s 是一个 %s\n", name, interf.Name())
    } else {
        fmt.Printf("%s 不是一个 %s\n", name, interf.Name())
    }
}

但是,如果可能的话,我认为使用类型切换(Type switch)更好。

英文:

You could use this to get a slice of interface types.

Then, you can just check whether the Type of your value implements the interface as in here:

interfaces := []reflect.Type{reflect.TypeOf((*Mover)(nil)).Elem(), 
    reflect.TypeOf((*Talker)(nil)).Elem(), 
    reflect.TypeOf((*Flyer)(nil)).Elem()}
p := &Person{}
t := reflect.TypeOf(p)
name := t.Elem().Name()
for _, interf := range interfaces {
    if t.Implements(interf) {
        fmt.Printf("%s is a %s\n", name, interf.Name())
    } else {
        fmt.Printf("%s is NOT a %s\n", name, interf.Name())
    }
}

But I think the use of a Type switch is preferable if at all possible

答案2

得分: 2

go不太擅长处理泛型。处理这个问题的首选方法是使用类型切换:

func testInterfaces2(entity interface{}) {
    switch entity.(type) {
    case Mover:
        fmt.Println("mover")
    case Talker:
        fmt.Println("talker")
    case Flyer:
        fmt.Println("flyer")
    default:
        fmt.Println("something else")
    }
}

但正如val所说,获取类型实现的所有接口的方法是(val代码的清理版本):

package main

import "fmt"
import "reflect"

type Mover interface  { Move() }
type Talker interface { Talk() }
type Flyer interface  { Fly() }

type Person struct{}
func (a *Person) Move() {fmt.Println("Moving...") }
func (a *Person) Talk() {fmt.Println("Talking...") }

func testInterfaces(entity interface{}, interfaces []reflect.Type) {
    t := reflect.TypeOf(entity)
    name := t.Elem().Name()
    for _, interf := range interfaces {
        if t.Implements(interf) {
            fmt.Printf("%s is a %s\n", name, interf.Name())
        } else {
            fmt.Printf("%s is NOT a %s\n", name, interf.Name())
        }
    }
}

func main() {
    interfaces := []reflect.Type{
        reflect.TypeOf((*Mover)(nil)).Elem(), 
        reflect.TypeOf((*Talker)(nil)).Elem(), 
        reflect.TypeOf((*Flyer)(nil)).Elem(),
    }
    p := &Person{}
    testInterfaces(p, interfaces)
}

在Go Play中可以查看:http://play.golang.org/p/6aqMx5CQvY

英文:

One thing that go doesn't handle exceptionally well is generics. The Prefered way to do this is a type switch:

func testInterfaces2(entity interface{}) {
    switch entity.(type) {
    case Mover:
        fmt.Println("mover")
    case Talker:
        fmt.Println("talker")
    case Flyer:
        fmt.Println("flyer")
    default:
        fmt.Println("something else")
    }
}

But like val said, the way to get all of the interfaces that are implemented by a type is (a cleaned up version of val's code):

package main

import "fmt"
import "reflect"

type Mover interface  { Move() }
type Talker interface { Talk() }
type Flyer interface  { Fly() }

type Person struct{}
func (a *Person) Move() {fmt.Println("Moving...") }
func (a *Person) Talk() {fmt.Println("Talking...") }

func testInterfaces(entity interface{}, interfaces []reflect.Type) {
	t := reflect.TypeOf(entity)
	name := t.Elem().Name()
	for _, interf := range interfaces {
    		if t.Implements(interf) {
        		fmt.Printf("%s is a %s\n", name, interf.Name())
    		} else {
        		fmt.Printf("%s is NOT a %s\n", name, interf.Name())
    		}
	}
}

func main() {
	interfaces := []reflect.Type{
		reflect.TypeOf((*Mover)(nil)).Elem(), 
		reflect.TypeOf((*Talker)(nil)).Elem(), 
		reflect.TypeOf((*Flyer)(nil)).Elem(),
	}
	p := &Person{}
	testInterfaces(p, interfaces)
}

Here it is in go play: http://play.golang.org/p/6aqMx5CQvY

huangapple
  • 本文由 发表于 2013年12月13日 23:32:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/20570193.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定