【问题标题】:In Scala, member of a class is not found when its instance is accessed from a list [Class]在 Scala 中,当从列表 [Class] 访问其实例时,找不到类的成员
【发布时间】:2013-01-24 22:29:32
【问题描述】:

我有一种感觉,我面临的问题与 Scala 的 Type Erasure 有关,但作为一个新手,我不能指望它。在这里需要一些帮助。

一、代码:

    class C (val i: Int) {
          def mkString() = { println("C.i =" + this.i) }

    object C {
               implicit val cOrdering = new Ordering [C] 
               {
                   def compare (a: C, b: C)= 
                   {
                        a.i compare b.i;
                   }
               }

然后,我创建另一个类,其中包含一个类“C”的集合:

    class  ContainerOfC [C] (s:Int) (implicit ordering: cOrdering[C]) {

               var internalCollection = new TreeSet[C]()

               def + (c:C): ContainerOfC [C] = {
                   this.internalCollection += c
                   this
               }

               def mkStringOfElems () = {

                   val y = this.internalCollection.toList

                   println (y.head.i) // <--- Problem here

                }

            }

这是 REPL 告诉我的:

error: value i is not a member of type parameter C
                                    println(y.head.i)
                                                   ^

我已经检查了 'y' 的类型:它是一个 List[C]。如果是这样,为什么我不允许访问“i”?它是一个构造参数好吧,但它是一个val,因此可以被视为一个成员变量,不是吗?

我浏览了论坛中的其他一些相关帖子,清单和类型标签是可能的出路。但是,对于这个简单的用例,我不确定是否需要达到那个级别。

【问题讨论】:

  • 你知道...我很想回答这个问题,但你的代码格式严重错误,无法编译。你能把它清理干净,让它完整和独立(包括所需的进口)吗? (特别是,不要使用语言不需要的大括号。)
  • @RandallSchulz:代码无法编译,因为它无法编译,而这正是问题所在。不过,我应该添加“导入” - 感谢您指出这一点 - 额外的标签是从 REPL 匆忙复制的结果。当我问下一个时,我会记住这一点。

标签: scala collections types type-erasure


【解决方案1】:

这有一种“去过那里,做过那个”的奇怪而熟悉的感觉。

你尝试改变这个怎么样:

class  ContainerOfC [C] (s:Int) (implicit ordering: cOrdering[C]) { ... }

对此没有声明中的类型参数C

class  ContainerOfC(s:Int) (implicit ordering: cOrdering[C]) { ... }

您展示的代码创建了一个类和特定类型C。当您稍后编写class ContainerOfC[C] 时,C 是一个可以由任何其他标识符命名的类型参数。这与定义class ContainerOfC[A] 相同,其中A 与前面代码中定义的类/类型C 没有任何关系。在您的示例中,类型参数C 将隐藏之前定义的类的名称...错误消息表明C 没有值i,这是因为编译器没有引用相同的@ 987654334@ 比你想象的要多。

编辑:让您快速了解我们是否在同一页面上而不会陷入其他编译错误,这里有一些编辑可以使代码编译并使用更常用的缩进和大括号样式:

class C(val i: Int) {
  def mkString() = println("C.i =" + this.i)
}

object C {
  implicit val cOrdering = new Ordering[C] {
    def compare(a: C, b: C) = a.i compare b.i
  }
}

class ContainerOfC(s: Int)(implicit ordering: Ordering[C]) {
  var internalCollection = new collection.mutable.TreeSet[C]()

  def +(c: C): ContainerOfC = {
    this.internalCollection += c
    this
  }

  def mkStringOfElems() = {
    val y = this.internalCollection.toList
    println(y.head.i)
  }
}

【讨论】:

  • 非常感谢。我已经在 StackOverflow 中讨论过这个主题,但我没有想到。在这种情况下编译器不应该发出警告吗?你怎么看?感谢另外两个帐户:努力缩进代码和如此迅速地回答。我很不安。顺便说一句,我试图提到你的名字为@huynjhl,但编辑由于某种原因没有认出。
  • @Nirmalya,是的,我认为编译器警告会很棒。我已经为此打开了一个功能请求:issues.scala-lang.org/browse/SI-5691.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-18
  • 2012-09-03
  • 1970-01-01
  • 2016-09-09
  • 1970-01-01
相关资源
最近更新 更多