为什么值不是 ArrayBuffer[Any] 中 class 的成员
Why value is not a member of class in ArrayBuffer[Any]
我刚开始学习 Scala。在 类 中,具有 val
和 var
的主构造函数参数是 public,而没有 val
或 var
的参数是私有值。所以,当我尝试执行以下代码时,一切都应该正常工作。
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
为什么会这样?
ArrayBuffer.empty[Any]
指定数组缓冲区正在存储 Any
值,而不是 Cat
s 和 Dog
s,并且 Any
不知道 [=18] =].尝试通过 Animal
特征将 Cat
和 Dog
相关联
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
这一行:
val animals = ArrayBuffer.empty[Any]
// ↑↑↑
您明确告诉 Scala 您的 animals
ArrayBuffer
可以包含 Any
对象。结果只能使用Any
which are not that many.
的方法
例如,将 Int
放入 animals
中是完全合法的,因为您告诉 Scala animals
的内容可以是任何内容。但是,Int
没有 name
方法,因此如果您尝试获取 Int
的名称,您的代码将在运行时崩溃。为了防止您的代码在运行时崩溃,Scala 决定一开始就不允许您编写该代码。
因此,您需要告诉 Scala 您要将什么 种东西放入 animals
。不幸的是,我们这里只有两个明确的名义类型可供我们使用:Dog
和 Cat
。但是,当你输入 animals
为 ArrayBuffer[Dog]
时,你不能将 Sally 放在那里,如果你输入 ArrayBuffer[Cat]
,则你不能将 Harry 放在那里。
所以,我们需要输入 animals
作为允许 Dog
s 和 Cat
s 的东西。
在 Scala 3 中,你可以使用 Union Type:
val animals = ArrayBuffer.empty[Dog | Cat]
唉,Scala 3 还差得远呢。
另一种方法是使用 Compound type with structural refinement:
val animals = ArrayBuffer.empty[{val name: String}]
这允许您的代码工作,但它可能不一定做您想要的:这允许 任何对象 有一个 val
命名为 name
String
类型,而不仅仅是 Dog
和 Cat
类型。特别是,您可以在 animals
中放入一些不是动物的东西,只要它有名字即可。
最好的方法可能是引入一个抽象超类型(我们称之为 Pet
),它定义了一个被 Cat
和 Dog
覆盖的抽象 val name
, 然后键入 animals
作为 ArrayBuffer[Pet]
:
trait Pet {
val name: String
}
class Dog(val name: String) extends Pet
class Cat(val name: String) extends Pet
val animals = ArrayBuffer.empty[Pet]
我刚开始学习 Scala。在 类 中,具有 val
和 var
的主构造函数参数是 public,而没有 val
或 var
的参数是私有值。所以,当我尝试执行以下代码时,一切都应该正常工作。
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
为什么会这样?
ArrayBuffer.empty[Any]
指定数组缓冲区正在存储 Any
值,而不是 Cat
s 和 Dog
s,并且 Any
不知道 [=18] =].尝试通过 Animal
特征将 Cat
和 Dog
相关联
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
这一行:
val animals = ArrayBuffer.empty[Any]
// ↑↑↑
您明确告诉 Scala 您的 animals
ArrayBuffer
可以包含 Any
对象。结果只能使用Any
which are not that many.
例如,将 Int
放入 animals
中是完全合法的,因为您告诉 Scala animals
的内容可以是任何内容。但是,Int
没有 name
方法,因此如果您尝试获取 Int
的名称,您的代码将在运行时崩溃。为了防止您的代码在运行时崩溃,Scala 决定一开始就不允许您编写该代码。
因此,您需要告诉 Scala 您要将什么 种东西放入 animals
。不幸的是,我们这里只有两个明确的名义类型可供我们使用:Dog
和 Cat
。但是,当你输入 animals
为 ArrayBuffer[Dog]
时,你不能将 Sally 放在那里,如果你输入 ArrayBuffer[Cat]
,则你不能将 Harry 放在那里。
所以,我们需要输入 animals
作为允许 Dog
s 和 Cat
s 的东西。
在 Scala 3 中,你可以使用 Union Type:
val animals = ArrayBuffer.empty[Dog | Cat]
唉,Scala 3 还差得远呢。
另一种方法是使用 Compound type with structural refinement:
val animals = ArrayBuffer.empty[{val name: String}]
这允许您的代码工作,但它可能不一定做您想要的:这允许 任何对象 有一个 val
命名为 name
String
类型,而不仅仅是 Dog
和 Cat
类型。特别是,您可以在 animals
中放入一些不是动物的东西,只要它有名字即可。
最好的方法可能是引入一个抽象超类型(我们称之为 Pet
),它定义了一个被 Cat
和 Dog
覆盖的抽象 val name
, 然后键入 animals
作为 ArrayBuffer[Pet]
:
trait Pet {
val name: String
}
class Dog(val name: String) extends Pet
class Cat(val name: String) extends Pet
val animals = ArrayBuffer.empty[Pet]