【问题标题】:Why value is not a member of class in ArrayBuffer[Any]为什么值不是 ArrayBuffer[Any] 中类的成员
【发布时间】:2019-06-09 08:48:30
【问题描述】:

我刚刚开始学习 scala。在类中,带有valvar 的主要构造函数参数是公共的,而没有valvar 的参数是私有值。因此,当我尝试执行以下代码时,一切正常。

import scala.collection.mutable.ArrayBuffer

class Cat(val name: String)
class Dog(val name: String)

val dog = new Dog("Harry")
val cat = new Cat("Sally")

val animals = ArrayBuffer.empty[Any]
animals.append(dog)
animals.append(cat)
animals.foreach(pet => println(pet.name))

但我收到以下错误:

ScalaFiddle.scala:12: error: value name is not a member of scala.this.Any
  animals.foreach(pet => println(pet.name))  // Prints Harry Sally

为什么会这样?

【问题讨论】:

  • 您使用参数“Any”对“ArrayBuffer”进行了参数化,因此现在“pet”被编译器视为“Any”,但“Any”中没有“name”字段。您需要包含两个宠物的“名称”的通用超类型,并用它参数化“ArrayBuffer”而不是“Any”

标签: scala class-hierarchy


【解决方案1】:

ArrayBuffer.empty[Any] 指定数组缓冲区存储Any 值,而不是Cats 和Dogs,并且Any 不知道name。尝试通过 Animal 特征关联 CatDog 像这样

trait Animal {
  val name: String
}
class Cat(val name: String) extends Animal
class Dog(val name: String) extends Animal

然后像这样指定数组缓冲区来存储Animal

val animals = ArrayBuffer.empty[Animal]
animals.append(dog)
animals.append(cat)
animals.foreach(pet => println(pet.name))

哪个输出

Harry
Sally

【讨论】:

  • ArrayBuffer.empty[Any]append怎么能添加dogcat
  • Any 是 Scala 类层次结构的根,所以 DogCat 自动成为 Any
【解决方案2】:

在这一行:

val animals = ArrayBuffer.empty[Any]
//                              ↑↑↑

你明确告诉 Scala 你的 animals ArrayBuffer 可以包含 Any 对象。结果只能使用Anywhich are not that many的方法。

例如,将Int 放入animals 是完全合法的,因为您告诉Scala animals 的内容可以是任何东西。但是,Int 没有name 方法,因此如果您尝试获取Int 的名称,您的代码会在运行时崩溃。为了防止您的代码在运行时崩溃,Scala 宁愿一开始就不允许您编写该代码。

所以,你需要告诉 Scala 什么你想把什么东西放进animals。不幸的是,我们这里只有两种明确的名义类型可供使用:DogCat。但是,当你将animals 输入为ArrayBuffer[Dog] 时,你无法将Sally 输入其中,如果输入为ArrayBuffer[Cat],则无法将Harry 输入其中。

因此,我们需要输入 animals 以允许 Dogs 和 Cats 使用。

在 Scala 3 中,您可以使用 Union Type:

val animals = ArrayBuffer.empty[Dog | Cat]

唉,Scala 3 还很遥远。

另一种方法是使用Compound type with structural refinement

val animals = ArrayBuffer.empty[{val name: String}]

这允许你的代码工作,但它不一定能做你想要的:这允许 任何对象 有一个名为 name 类型为 Stringval,而不仅仅是 @ 987654349@s 和Cats。特别是,您可以在animals 中添加一些不是动物的东西,只要它有名字即可。

最好的方法可能是引入一个抽象超类型(我们称之为Pet),它定义了一个被CatDog覆盖的抽象val name,然后键入animals为@987654357 @:

trait Pet {
  val name: String
}

class Dog(val name: String) extends Pet
class Cat(val name: String) extends Pet

val animals = ArrayBuffer.empty[Pet]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-16
    • 1970-01-01
    • 1970-01-01
    • 2022-10-22
    • 2021-08-20
    • 1970-01-01
    • 2011-02-06
    • 1970-01-01
    相关资源
    最近更新 更多