隐式定义适用于Seq但不适用于Set [英] Implicit definition working for Seq but not for Set
问题描述
因此,我为它们做了一些实用程序类和隐式转换.但是,尽管从代码序列相同,但从Seq而不是Set转换时,它的效果很好,乍一看,这两个特征看起来相当相似.可能是什么问题,我该如何解决?
So I've made some utility classes and implicit conversions for them. However, it works fine when converting from a Seq but not from a Set, although the code is the same, and those two traits seem rather similar at first sight. What could be the problem, and how would I fix it?
import scala.collection.mutable.HashMap
trait Indexed[T] {
def index: T
}
class IndexMap[T, V <: Indexed[T]] extends HashMap[T, V] {
override def put(key: T, value: V): Option[V] = {
require(key == value.index)
super.put(key, value)
}
final def put(value: V): Option[V] = put(value.index, value)
}
trait Named extends Indexed[String] {
final def index = name
def name: String
}
type NameMap[T <: Named] = IndexMap[String, Named]
这很好:
implicit def seq2IndexMap[T, V <: Indexed[T]](s: Seq[V]): IndexMap[T,V] = {
val ret = new IndexMap[T,V]();
s.foreach(v => ret.put(v))
ret
}
但是,这无法使用type mismatch; found : scala.collection.immutable.Set[Program.ClassData] required: Common.NameMap[Program.ClassData] (which expands to) Common.IndexMap[String,Common.Named]
implicit def set2IndexMap[T, V <: Indexed[T]](s: Set[V]): IndexMap[T,V] = {
val ret = new IndexMap[T,V]();
s.foreach(v => ret.put(v))
ret
}
输入时:
val c = Class("Test", Set(ClassData("data1", null), ClassData("data2", null)))
ClassData
扩展Named
的位置.
我正在使用Scala 2.10.
I'm using Scala 2.10.
为方便起见,简化了Class和ClassData的定义:
The simplified definitions of Class and ClassData for convenience:
case class ClassData(name: String, p: Any) extends Named
case class Class(n: String, data: NameMap[ClassData])
好的,我们发现了问题.确实是因为Set
是不变的(我不明白为什么).
Edit 2:
Ok, we found the problem. It was indeed because Set
is invariant (which I don't understand why).
当我写Set(ClassData("data1", null))
时,它生成了一个Set[ClassData]
,它不能解释为Set[Named]
,但是它与Seq
一起工作,因为Seq
是协变的.
When I wrote Set(ClassData("data1", null))
, it made a Set[ClassData]
, which could not be interpreted as a Set[Named]
, whereas it worked with Seq
because Seq
is covariant.
有趣的是,当我们明确调用转换时,Scala没有任何问题:
Interestingly enough, Scala doesn't have any problem when we explicitly call the conversion:
val c = Class("Test", set2IndexMap((Set(ClassData("data1", null), ClassData("data2", null))))
在这种情况下,我认为Scala能够推断出Set
的类型.在我看来,这表明Scala可能太复杂了.如果我的显式版本也有错误,我可以立即看到隐式转换出了什么问题.我觉得幕后发生了太多事情,最终您必须了解它们,否则您将陷于此类问题.
I think Scala is able, in this case, to infer which type of Set
to infer. In my opinion, this shows how Scala can be too complex. If I also had an error with the explicit version, I could have immediately seen what was wrong with the implicit conversion. I feel like too many things happen behind the scenes, and ultimately you have to know them or you'll get stuck with problems like this.
一种解决方案是显式声明集合的类型:
A solution was to explicitly state the type of the set:
val c = Class("Test", Set[Named](ClassData("data1", null), ClassData("data2", null)))
一个更好的解决方案是使隐式转换适用于Iterable
甚至Traversable
,这是Seq
和Set
的超特性,并且 是协变的(尽管Set
不是,而作为 Iterable
协变.
A better solution was to make the implicit conversion work for Iterable
or even Traversable
, which are super traits of both Seq
and Set
, and are covariant (although Set
is not, while being covariant as a Iterable
).
implicit def set2IndexMap[T, V <: Indexed[T]](s: Traversable[V]): IndexMap[T,V] = {
val ret = new IndexMap[T,V]();
s.foreach(v => ret.put(v))
ret
}
推荐答案
臭名昭著的是,Set
的类型参数是不变的.
Infamously, Set
is invariant in its type parameter.
那似乎使隐式不适用?
也许V
无法正确推断.有时它喜欢推断Nothing
.
Maybe V
is not inferred correctly. Sometimes it likes to infer Nothing
.
(发布完整的最小化内容将有助于某人为您提供帮助.)
(Posting a complete minimization would help someone help you.)
如果有机会,我会尝试破译-Ytyper-debug
,但是FTR:
I'll try to decipher the -Ytyper-debug
when I get a chance, but FTR:
在Seq上成功:
| | | solving for (A: ?A)
| | | |-- seq2IndexMap BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value b in Test) implicits disabled
| | | | [adapt] [T, V <: Code.this.Indexed[T]](s: Seq[V])Code.this.IndexM... adapted to [T, V <: Code.this.Indexed[T]](s: Seq[V])Code.this.IndexM...
| | | | \-> (s: Seq[V])nosetconvert.Test.IndexMap[T,V]
| | | solving for (T: ?T, V: ?V)
| | | [adapt] seq2IndexMap adapted to [T, V <: Code.this.Indexed[T]](s: Seq[V])Code.this.IndexM... based on pt Seq[nosetconvert.Test.ClassData] => nosetconvert.Test.NameMap[nosetconvert.Test.ClassData]
| | | |-- [T, V <: Code.this.Indexed[T]](s: Seq[V])Code.this.IndexM... : pt=nosetconvert.Test.NameMap[nosetconvert.Test.ClassData] BYVALmode-EXPRmode (silent: value b in Test) implicits disabled
| | | | \-> nosetconvert.Test.IndexMap[String,nosetconvert.Test.Named]
| | | [adapt] [A](elems: A*)CC[A] adapted to [T, V <: Code.this.Indexed[T]](s: Seq[V])Code.this.IndexM... based on pt nosetconvert.Test.NameMap[nosetconvert.Test.ClassData]
| | | \-> nosetconvert.Test.IndexMap[String,nosetconvert.Test.Named]
设置失败:
| | | solving for (A: ?A)
| | | |-- set2IndexMap BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value c in Test) implicits disabled
| | | | [adapt] [T, V <: Code.this.Indexed[T]](s: Set[V])Code.this.IndexM... adapted to [T, V <: Code.this.Indexed[T]](s: Set[V])Code.this.IndexM...
| | | | \-> (s: Set[V])nosetconvert.Test.IndexMap[T,V]
| | | |-- nosetconvert.this.Test.set2IndexMap BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value c in Test) implicits disabled
| | | | [adapt] [T, V <: Code.this.Indexed[T]](s: Set[V])Code.this.IndexM... adapted to [T, V <: Code.this.Indexed[T]](s: Set[V])Code.this.IndexM...
| | | | \-> (s: Set[V])nosetconvert.Test.IndexMap[T,V]
| | | \-> <error>
这篇关于隐式定义适用于Seq但不适用于Set的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!