【问题标题】:Scala Array with different data types具有不同数据类型的 Scala 数组
【发布时间】:2017-02-05 07:58:55
【问题描述】:

*我们知道 scala 数组包含相同类型的数据。但是当我将数组声明为

var a = new Array[Any](3)

我能够存储不同的数据类型。

a(0)=5
a(1)="hello"
a(2)=1.5

这怎么可能?如果它是错误的,那么我们在 scala 中存储不同数据类型的选项是什么?*

【问题讨论】:

  • 我认为这个问题的正确答案太宽泛了。请参阅众多 Scala 教程之一
  • 您的问题表明您认为一个值只有一个唯一的类型。但事实并非如此——在具有子类型化的语言中,一个值可以同时是多种类型的成员。

标签: arrays scala any


【解决方案1】:

“相同类型”的概念始终取决于一定程度的概括性。在 Scala 中,通用程度由形式类型决定。

3 和 7 “属于同一类型”吗?如果我们写...

val a : Int = 3
val b : Int = 7

那么它们属于同一类型Int。但是,如果我们定义位长受限的Int 类型(我们非常欢迎在 Scala 中这样做),我们可能会这样写

val a : Int2 = 3
val b : Int3 = 7

它们似乎不再属于同一类型!

如果我们定义继承层次结构

trait Animal;
class Dog extends Animal;
class Frog extends Animal;

那么DogFrog 有相同的类型吗?如果我们写

val d : Dog  = new Dog
val f : Frog = new Frog

然后看起来答案是否定的。但是如果我们写

val d : Animal = new Dog
val f : Animal = new Frog

然后它们看起来确实具有相同的类型。与此一致,如果我声明一个像

这样的数组
val arr : Array[Dog] = Array.ofDim[Dog](5)

那我不能把青蛙放进去,因为青蛙不是狗。但是如果我声明一个类似的数组

val arr : Array[Animal] = Array.ofDim[Animal](5)

那么当然青蛙和狗都可以进去,因为在Animal的泛化水平上,青蛙和狗确实是同一类型。

在 Scala 中,Any 是所有其他类型派生的基本类型。因此,在非常高的通用性上,5"hello"1.5 都具有相同的类型 Any,就像在高级通用性时 FrogDog 具有相同的类型输入Animal。所以将5"hello"1.5 放入Array[Any] 是没有问题的。

【讨论】:

    【解决方案2】:

    是的,您对scala array 的看法是正确的,并且您确实在此处存储了same type 的数据。看这个例子:

    scala> val a = Array(5,"hello",1.5)
    a: Array[Any] = Array(5, hello, 1.5)
    

    我们没有看到包含integerstringdouble 的数组被创建。我们看到创建了一个array of Any。在array creation 期间,scala 编译器寻找nearest common supertype in hierarchy 以满足它可以hold elements of same type only 的Array 的属性。在这种情况下,Any 是所有类的超类型,满足条件。并且,如果编译器找不到公共超类型,数组创建将失败。

    请注意,它不仅适用于 Array,也适用于存储 same types 的其他 collections。例如:List

    scala> val list = List(5,"hello",1.5)
    list: List[Any] = List(5, hello, 1.5)
    

    我们在 scala 中存储不同数据类型的选项是什么?

    如您所见,我们无法在ListArray 中使用preserve the type of elements。所有元素都存储为Any。为了保留元素的类型并将它们存储在一起,scala 为我们提供了Tuple

    scala> val tuple = (5,"hello",1.5)
    tuple: (Int, String, Double) = (5,hello,1.5)
    

    【讨论】:

    • 支持不同类型的数组是否是一种好习惯(除非您的示例中存在层次结构)?这可能导致脏铸造错误
    【解决方案3】:

    正如其他人已经回答了为什么 Array[Any] 可以包含 String、Boolean、Int 等类型的元素。让我回答问题的以下部分

    如果它是错误的,那么我们在 scala 中存储的选项是什么 不同的数据类型?*

    最明显的答案是Shapeless library。 Shapeless 支持称为HList 的高级数据结构,您可以使用它在列表中存储异构类型,而不会丢失类型信息。

    例如看下面的sn-p

    scala> import shapeless.{::, HList, HNil}
    import shapeless.{$colon$colon, HList, HNil}
    
    scala> val list = 1 :: "a" :: true :: HNil
    list: shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.HNil]]] = 1 :: a :: true :: HNil
    
    scala> list.head
    res0: Int = 1 // notice the type of the element is Int and not Any
    
    scala> list.tail.head
    res1: String = a
    
    scala> list.tail.tail.head
    res2: Boolean = true
    

    在上面的代码中,您有一个 HList 类型的 val list,其中包含 IntStringBoolean 类型的三个元素。并且当您检索 HList 的元素时,元素的原始类型将被保留,并且您不会像数组一样获得像 Any 这样的泛型类型。这是可能的,因为HList 不仅存储数据,还存储元素的类型信息,并在检索时正确地转换它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-24
      • 2015-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-08
      • 1970-01-01
      相关资源
      最近更新 更多