【问题标题】:How to initialize a generic array with a default value in Scala如何在 Scala 中使用默认值初始化泛型数组
【发布时间】:2016-12-28 18:43:45
【问题描述】:

我在尝试使用泛型类型初始化数组并将其存储在值 (val) 中时遇到问题

case class Matrix[T <: AnyVal](val structure : Array[Array[Array[T]]])

//A method in another class
def foo() : Unit = {
    val aux: Array[Array[Array[T]]] = Array.fill(this.structure.length, this.structure.head.length, this.structure.head.head.length)(null)
    ...
    ...
}

问题是,当试图创建一个类型为 T 的数组时,我想用默认值 null 来初始化它,但它说:

Array[Array[Array[T]]] 类型的表达式不符合预期的 Array[Array[Array[T]]]]

我该如何解决这个问题?谢谢

【问题讨论】:

  • AnyVals 不能是null
  • 你是对的。我只是注意到了。但是,对于 AnyVal,哪个相当于 null by?
  • 您正在寻找AnyRef
  • 仍然抛出类型不匹配:找到 Null(null),需要:T
  • 如果您谈论的是val aux,那么也许您应该声明您的T。感觉您在这里遗漏了太多代码,我们无法为您提供帮助。

标签: arrays scala generics


【解决方案1】:

T:Numeric

如果我是你,我会将 T 限制为 Numeric 类型,然后使用 zero 值作为空矩阵的默认值:

scala> :pa
// Entering paste mode (ctrl-D to finish)

import scala.reflect.ClassTag

class Matrix[T:Numeric](val structure: Array[Array[T]])
{
    def *(that: Matrix[T]): Matrix[T] = ???
    def +(that: Matrix[T]): Matrix[T] = ???
    override def toString: String = structure.map(_.mkString(",")).mkString("\n")
}

object Matrix
{
    def apply[T:Numeric:ClassTag](rows: Int, cols: Int): Matrix[T] =
    {
        val zero: T = implicitly[Numeric[T]].zero
        new Matrix[T](Array.fill[T](rows, cols)(zero))
    }

    def apply[T:Numeric](data: Array[Array[T]]): Matrix[T] = new Matrix(data)
}

// Exiting paste mode, now interpreting.

import scala.reflect.ClassTag
defined class Matrix
defined object Matrix

scala> val empty = Matrix[Int](3,3)
empty: Matrix[Int] =
0,0,0
0,0,0
0,0,0

scala> val ex = Matrix[Int](Array(Array(1,2), Array(3,4)))
ex: Matrix[Int] =
1,2
3,4

T &lt;: AnyRef

否则,如果您想使用null 作为默认值的非数字值,您可以执行以下操作:

scala> :pa
// Entering paste mode (ctrl-D to finish)

import scala.reflect.ClassTag

class Matrix[T >: Null <: AnyRef](val structure : Array[Array[T]])
{
    override def toString: String = structure.map(_.mkString(",")).mkString("\n")
}

object Matrix
{
    def apply[T >: Null <: AnyRef : ClassTag](rows: Int, cols: Int): Matrix[T] =
    {
        new Matrix[T](Array.fill[T](rows, cols)(null))
    }

    def apply[T >: Null <: AnyRef](data: Array[Array[T]]): Matrix[T] = new Matrix(data)
}

// Exiting paste mode, now interpreting.

import scala.reflect.ClassTag
defined class Matrix
defined object Matrix

scala> case class Person(name: String)
defined class Person

scala> val empty = Matrix[Person](3,3)
empty: Matrix[Person] =
null,null,null
null,null,null
null,null,null

scala> val data = Array(Array(Person("a"), Person("b")), Array(Person("c"), Person("d")))
data: Array[Array[Person]] = Array(Array(Person(a), Person(b)), Array(Person(c), Person(d)))

scala> val ex = Matrix[Person](data)
ex: Matrix[Person] =
Person(a),Person(b)
Person(c),Person(d)

请注意,您必须通过添加绑定的T &gt;: Null 手动指定T 可以是Null 的超类型。

【讨论】:

  • 问题是我想使用矩阵来包含其他数据类型,而不仅仅是数值。这就是为什么我想用默认值初始化一个数组,并将其分配给一个变量(或本例中的值)
  • 很公平,但一般的想法仍然认为您的默认值需要是 T 类型(因此,如果您可以将 T 限制为您的数据的某些严格的超类型,然后使用那个超类型的值那么这将是理想的)
  • 例如,在 Java 中,所有的类都有 Object,就像最后一个父级一样。因此,创建数组时 Object 的默认值为 null。在 Scala 中,哪个是默认值?应该有类似的东西。我知道 Scala“不喜欢”空值,这就是他们使用 Options 的原因,但我认为应该有一个像 null 这样的默认值,但对于 Scala。
  • 你需要说它可以是null 明确地使用T &gt;: Null &lt;: AnyRef,看我更新的答案
  • @Malvrok 这能回答你的问题吗?
【解决方案2】:

如果您想要默认值,只需使用Array.ofDim(this.structure.length, this.structure.head.length, this.structure.head.head.length) 而不是Array.fill。值将是,如在 Java 中,null 用于对象,0 用于Int0.0 用于Double,等等。它也更便宜。

你需要一个ClassTag[T] 在范围内,但你也需要fill

【讨论】:

    猜你喜欢
    • 2012-05-15
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-21
    相关资源
    最近更新 更多