Use map[string]SpecificType with method of map[string]SomeInterface into

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

Use map[string]SpecificType with method of map[string]SomeInterface into

问题

我在下面的代码中遇到了cannot use map[string]MyType literal (type map[string]MyType) as type map[string]IterableWithID in argument to MapToList错误,我该如何将具体的map类型传递给期望接口类型的方法?

https://play.golang.org/p/G7VzMwrRRw

英文:

I get cannot use map[string]MyType literal (type map[string]MyType) as type map[string]IterableWithID in argument to MapToList with the code below, how do I pass in a concrete map type to method that expects a interface type?

https://play.golang.org/p/G7VzMwrRRw

答案1

得分: 1

Go的接口约定与Java不太相同(设计者显然不太喜欢使用getter和setter的想法:-/)。所以你有两个核心问题:

  1. map[string]Foo与map[string]Bar不同,即使Bar实现了Foo,所以你需要稍微处理一下(先使用make(),然后在单个赋值中进行赋值)。
  2. 接口方法是按值调用的,没有指针,所以你真的需要在调用者中使用foo = foo.Method(bar),或者在实现类似功能时使用指针。

你可以做一些近似模拟你想要的功能:

type IterableWithID interface {
    SetID(id string) IterableWithID     // 使用方式为 foo = foo.SetID(bar)
}

func (t MyType) SetID(id string) IterableWithID {
    t.ID = id
    return t
}

...解决类型问题

t := make(map[string]IterableWithID)
t["foo"] = MyType{}
MapToList(t)              // 这是一个map[string]IterableWithID,所以编译器很高兴。

...最后...

value = value.SetID(key)  // 我们设置回我们改变的值的副本

value= 处理了方法获得的是值对象的新副本的事实,所以原始对象不会受到你的方法的影响(更改将会消失)。

Go Playground上更新的代码

...但这并不是特别符合Go的习惯--他们真的希望你只引用结构体成员,而不是使用Java风格的接口中的mutators(尽管说实话,我对这个小细节不是很热衷--mutators非常方便进行验证)。

英文:

Go's interface convention doesn't quite work the same way as in, say, Java (and the designers apparently didn't like the idea of getters and setters very much :-/ ). So you've got two core problems:

  1. A map[string]Foo is not the same as a map[string]Bar, even if Bar implements Foo, so you have to break it out a bit (use make() beforehand, then assign in a single assignment).
  2. Interface methods are called by value with no pointers, so you really need to do foo = foo.Method(bar) in your callers or get really pointer-happy to implement something like this.

What you can do to more-or-less simulate what you want:

type IterableWithID interface {
    SetID(id string) IterableWithID     // use as foo = foo.SetID(bar)
}

func (t MyType) SetID(id string) IterableWithID {
    t.ID = id
    return t
}

...and to deal with the typing problem

t := make(map[string]IterableWithID)
t["foo"] = MyType{}
MapToList(t)              // This is a map[string]IterableWithID, so compiler's happy. 

...and finally...

value = value.SetID(key)  // We set back the copy of the value we mutated

The final value= deals with the fact that the method gets a fresh copy of the value object, so the original would be untouched by your method (the change would simply vanish).

Updated code on the Go Playground

...but it's not particularly idiomatic Go--they really want you to just reference struct members rather than use Java-style mutators in interfaces (though TBH I'm not so keen on that little detail--mutators are supes handy to do validation).

答案2

得分: 1

你不能做你想做的事情,因为这两种映射类型是不同的。即使其中一个的元素类型是实现了另一个元素类型的接口的类型也没有关系。你传递给函数的映射类型必须是map[string]IterableWithID。你可以创建一个该类型的映射,将类型为MyType的值赋给映射,并将其传递给函数。

参见 https://play.golang.org/p/NfsTlunHkW

另外,你可能不想在MapToList中返回一个切片的指针,而是直接返回切片本身。切片包含对底层数组的引用。

英文:

You can't do what you want to do because the two map types are different. It doesn't matter that the element type of one is a type that implements the interface which is the element type of the other. The map type that you pass into the function has to be map[string]IterableWithID. You could create a map of that type, assign values of type MyType to the map, and pass that to the function.

See https://play.golang.org/p/NfsTlunHkW

Also, you probably don't want to be returning a pointer to a slice in MapToList. Just return the slice itself. A slice contains a reference to the underlying array.

huangapple
  • 本文由 发表于 2016年9月9日 09:20:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/39402443.html
匿名

发表评论

匿名网友

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

确定