【问题标题】:Implicit definition working for Seq but not for Set隐式定义适用于 Seq 但不适用于 Set
【发布时间】:2014-04-24 16:00:36
【问题描述】:

所以我为它们做了一些实用程序类和隐式转换。然而,当从 Seq 而不是从 Set 转换时,它工作得很好,尽管代码是相同的,而且这两个特征乍一看似乎非常相似。可能是什么问题,我该如何解决?

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。

编辑:

为方便起见,对 Class 和 ClassData 的简化定义:

case class ClassData(name: String, p: Any) extends Named
case class Class(n: String, data: NameMap[ClassData])

编辑 2:

好的,我们找到了问题。确实是因为Set 是不变的(我不明白为什么)。

当我写Set(ClassData("data1", null)) 时,它生成了一个Set[ClassData],它不能解释为Set[Named],而它与Seq 一起工作,因为Seq 是协变的。

有趣的是,当我们显式调用转换时,Scala 没有任何问题:

val c = Class("Test", set2IndexMap((Set(ClassData("data1", null), ClassData("data2", null))))

在这种情况下,我认为 Scala 能够推断出要推断的 Set 的类型。在我看来,这表明 Scala 可能过于复杂。如果我对显式版本也有错误,我可以立即看到隐式转换有什么问题。我觉得幕后发生的事情太多了,最终你必须了解它们,否则你会遇到这样的问题。

一种解决方案是明确说明集合的类型:

val c = Class("Test", Set[Named](ClassData("data1", null), ClassData("data2", null)))

更好的解决方案是使隐式转换适用于Iterable 甚至Traversable,它们是SeqSet 的超级特征,并且 协变的(尽管@ 987654342@ 不是,同时是协变的作为 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
}

【问题讨论】:

  • 您的第一个代码块无法编译。哪个HashMap 已导入但未显示?
  • 它是 scala.collection.mutable.HashMap,因为你可以看到我对其进行了变异。
  • 顺便说一句,您应该避免使用核心 Java 库名称,例如 Class(在 java.lang 中定义)。

标签: scala set implicit seq


【解决方案1】:

众所周知,Set 的类型参数是不变的。

这似乎使隐式不适用?

也许V 没有被正确推断出来。有时它喜欢推断Nothing

(发布完整的最小化可以帮助某人帮助您。)

有机会我会尝试破译-Ytyper-debug,但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>

【讨论】:

  • 完全最小化是什么意思?
  • @LP_ 我的意思是可以编译的东西。
  • 谢谢,这个问题确实是不变的(cf:edited question)。
猜你喜欢
  • 2021-12-19
  • 2022-01-17
  • 2019-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-02
  • 2011-02-14
相关资源
最近更新 更多