Call Go function that accepts a slice of interface A with a slice of struct B (B implements A)
我有以下类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | type Statement interface { Say() string } type Quote struct { quote string } func (p Quote) Say() string { return p.quote } func Replay(conversation []Statement) { for _, statement := range conversation { fmt.Println(statement.Say()) } } |
我认为我很清楚为什么接受
我们可以将引号显式转换为语句:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | conversation := []Quote{ Quote{"Nice Guy Eddie: C'mon, throw in a buck!"}, Quote{"Mr. Pink: Uh-uh, I don't tip."}, Quote{"Nice Guy Eddie: You don't tip?"}, Quote{"Mr. Pink: Nah, I don't believe in it."}, Quote{"Nice Guy Eddie: You don't believe in tipping?"}, } // This doesn't work // Replay(conversation) // Create statements from quotes statements := make([]Statement, len(conversation)) for i, quote := range conversation { statements[i] = quote } Replay(statements) |
号
现在假设重播是一个库的一部分,它希望在使用重播时有多容易走出自己的路。它允许您使用任何对象片调用重播,只要这些对象实现语句接口。为此,它具有以下转换方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | func ConvertToStatements(its interface{}) ([]Statement, error) { itsValue := reflect.ValueOf(its) itsKind := itsValue.Kind() if itsKind != reflect.Array && itsKind != reflect.Slice { return nil, fmt.Errorf("Expected items to be an Array or a Slice, got %s", itsKind) } itsLength := itsValue.Len() items := make([]Statement, itsLength) for i := 0; i < itsLength; i++ { itsItem := itsValue.Index(i) if item, ok := itsItem.Interface().(Statement); ok { items[i] = item } else { return nil, fmt.Errorf("item #%d does not implement the Statement interface: %s", i, itsItem) } } return items, nil } |
重播如下:
1 2 3 4 5 6 | func Replay(its interface{}) { conversation := ConvertToStatements(its) for _, statement := range conversation { fmt.Println(statement.Say()) } } |
。
我们现在可以直接调用带引号的重播:
1 | Replay(conversation) |
最后,我的问题是:是否有一种更简单的方法允许重播接受任何类型A的切片,只要A实现语句接口?
不同的数据布局意味着您不能交换这两种切片类型,甚至不能通过不安全的类型转换:如果您有一种类型并且需要另一种类型,则需要在它们之间手动转换。
你(长)问题的简短回答是:不。
我不认为你的转换状态和重放处理空接口的解决方案是一个"好"的解决方案:我更喜欢
下面的代码有两种不同的结构类型,它们都实现了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | package main import"fmt" type Statement interface { Say() string } type Statements []Statement type Quote struct { quote string } type Quotes []Quote func (p Quote) Say() string { return p.quote } type Attributed struct { who string quote string } func (p Attributed) Say() string { return p.who +":" + p.quote } func Replay(conversation []Statement) { for _, s := range conversation { fmt.Println(s.Say()) } } func (q Quotes) toStatements() Statements { conv := make(Statements, len(q)) for i, v := range q { conv[i] = Statement(v) } return conv } func main() { conversation := Statements{ Quote{"Nice Guy Eddie: C'mon, throw in a buck!"}, Quote{"Mr. Pink: Uh-uh, I don't tip."}, Attributed{"Nice Guy Eddie","You don't tip?"}, // <= another type Quote{"Mr. Pink: Nah, I don't believe in it."}, Quote{"Nice Guy Eddie: You don't believe in tipping?"}, } myquotes := Quotes{ Quote{"Nice Guy Eddie: C'mon, throw in a buck!"}, Quote{"Mr. Pink: Uh-uh, I don't tip."}, Quote{"Nice Guy Eddie: You don't tip?"}, Quote{"Mr. Pink: Nah, I don't believe in it."}, Quote{"Nice Guy Eddie: You don't believe in tipping?"}, } Replay(conversation) Replay(myquotes.toStatements()) } |