如何在 Scala 中声明一个包含数组的变量(val 或 var),就像它在 Java 中是 ArrayList<?> 一样?

时间:2021-05-26 05:24:22

标签: arrays scala

我从一本有效的书中提取了一个简单的测试程序:

def main(args: Array[String]) {
   val monTabEntiers = new Array[Int](30);
   val monTabEntiersInit = Array(1, 2, 5, 6);
   val monTabChaine = new Array[String](30);
   val lesSaisons = Array("été", "automne", "printemps", "hiver");

   println(monTabEntiers(0));
   println(monTabEntiersInit(0));
   println(monTabChaine(0));
   println(lesSaisons(0));

   monTabEntiersInit.update(0, 15);
   println(monTabEntiersInit(0));
...

但我决定改变它,因为我不喜欢松散类型的变量。

val monTabEntiers:Array[Int] = new Array(30);
val monTabEntiersInit = Array(1, 2, 5, 6);
val monTabChaine:Array[String] = new Array(30);
val lesSaisons:Array[String] = Array("été", "automne", "printemps", "hiver");

但我不知道如何处理 monTabEntiersInit 来声明(即使它的名字不是它的目标)一个 Array 任何东西。

我该如何更改?

val monTabEntiersInit = Array(1, 2, 5, 6);

我尝试过但没有成功:

val monTabEntiersInit:Array = Array(1, 2, 5, 6);

 Refused : type parameter is asked.
val monTabEntiersInit:Array[_] = Array(1, 2, 5, 6);

// fails on line :
monTabEntiersInit.update(0, 15);

 found   : Int(15)
 required: _$1

总而言之,我正在寻找这种类似 Java 的声明(大致编写,我没有检查下面的语法正确性):

List<?> monTabEntiersInit = new ArrayList<?>(List.of(1, 2, 5, 6));

拒绝这个:

var monTabEntiersInit = new ArrayList<?>(List.of(1, 2, 5, 6));

3 个答案:

答案 0 :(得分:3)

正确的注解是

val monTabEntiersInit: Array[Int] = Array(1, 2, 5, 6)

如果您真的希望 monTabEntiersInit 保存任何可能的值,那么简单的答案是使用 Any

val monTabEntiersInit: array[Any] = Array(1, 2, 5, 6)

然而,这几乎总是一个坏主意,最好收紧类型。如果您想保存两种可能类型中的一种,则可以使用 Either。如果您需要更多值,请考虑使用特征:

trait Value
case class StringValue(s: String) extends Value
case class IntValue(i: Int) extends Value
case class DoubleValue(d: Double) extends Value

val monTabEntiersInit: array[Value] = ...

然后您可以使用 match 计算出您要处理的值。

monTabEntiersInit(0) match {
  case StringValue(s) =>
     // process s
  case IntValue(i) =>
     // process i
  case DoubleValue(d) =>
    // process d
}

答案 1 :(得分:1)

首先,您的变量不是“松散输入”。类型注解在 Scala 中是可选的,但它仍然是严格类型的。

val monTabEntiersInit = Array(1, 2, 5, 6) // you don't need semi-colons

声明一个 Int 数组,它比您最终得到的 Array[Any] “松散输入”要少得多。后者太松散了,几乎总是应该避免:使用 Any 完全绕过了类型系统并使集合在很大程度上无法使用。

最后,您的问题不在于类型声明,而在于适当的变异变量。这是非常不寻常的,并且在 scala 中不受欢迎,而不是“scala 方式”。你应该避免这种情况。 注意,虽然

   val foo: Array[_] = Array(1,2,3)
   foo.update(0,0)

不起作用,像这样:

   val x = Array(1,2,3)
   val y = x.updated(0,0) // Still Array[Int]
   val z = x.updated(1, "one") // Now Array[Any]

不仅可以工作,而且是线程安全和引用透明的,而且还可以正确跟踪结果数组。

一般来说,除了您希望优化最后几毫秒性能的一些高度专业化的情况外,不要使用 Array,使用 Seq/List(对于顺序集合)、LazyList/Iterator(用于流式传输和/或迭代一次语义)、IndexedSeq/Vector(用于随机访问)。并且不要在任何地方改变事物。那只是……糟糕。

总而言之,一些在 Scala 中几乎通用的“经验法则”:

  • 不要使用Any
  • 不要在同一个集合中混合对象类型
  • 不要就地改变事物并避免可变结构(如 Array
  • 尽可能依赖 scala 类型推断,避免无故放宽类型约束的类型注释。

答案 2 :(得分:0)

它甚至不能在 Java 中编译如下:

ArrayList<?> list = new ArrayList(10);
list.set(0, "abc");

相反,你应该写成:

ArrayList<Object> list = new ArrayList<>(10);
list.set(0, "abc");

在Scala中:

val monTabEntiersInit:Array<Any> = Array(1, 2, 5, 6)
相关问题