【问题标题】:Scala: generic array inside traitScala:特征内的通用数组
【发布时间】:2014-06-14 01:51:56
【问题描述】:

可以构造subj吗?比如:

trait THasArray[T]
{
  val ARRAY_SIZE = 8
  val array = Array.fill[T](ARRAY_SIZE)(null)
}

效果不佳 - 编译器抱怨“null”,这是我需要的。我知道 Option,但问题是,这对于普通数组是否可行。

谢谢。

编辑:

谢谢你们,伙计们。 我已经发现了将类标签作为隐式参数传递的技巧。

不过,我已经重新制定了我原来的问题。我只需要将该数组初始化一次,并且永远不会更改。所以这是我的解决方案,它不需要隐式 val 类型标记,而是使用 init 函数来解决问题

trait THasArray[T >: Null]
{
  private var table: Seq[T] = null

  protected def init(elems: (Int, T)*)(implicit manifest: Manifest[T]) =
  {
    val size = (elems foldLeft 0)(_ max _._1)
    val array = Array.fill[T](size + 1)(null)
    elems foreach { x => array(x._1) = x._2 }
    table = array
  }
}

【问题讨论】:

  • “主题”是什么意思?

标签: scala scala-collections


【解决方案1】:

T 需要有Null 的下限,因为并非 Scala 中的所有值都可以为空。扩展AnyVal 的类型由不能为空的JVM 原语表示;例如,没有空 Int 这样的东西。

另外,看Array.fill的方法签名:

def fill[T: ClassTag](n: Int)(elem: => T): Array[T]

上下文绑定T: ClassTag 意味着fill 有一个ClassTag[T] 类型的隐式参数。 trait 的类型参数不能绑定上下文,所以不幸的是,当您继承 THasArray 时,您必须稍微费力才能将 ClassTag 纳入范围。

trait THasArray[T >: Null] {
  implicit def classTagT: ClassTag[T]
  val ARRAY_SIZE = 8
  lazy val array = Array.fill[T](ARRAY_SIZE)(null)
}

class Foo[T >: Null](implicit val classTagT: ClassTag[T])
  extends THasArray[T]

【讨论】:

  • 在另一条评论中你说强制转换不是必需的,但它仍然在你的代码中。
  • 哎呀,我的错。编辑删除它。
【解决方案2】:

首先,方法Array.fill 需要在范围内隐含ClassTag。其次,null 的类型为Null,因此您需要将其强制转换为T。第三,array 值应该是惰性的,因为 ClassTag 实例仅在 HasArray 创建时可用。

trait HasArray[T] {
  implicit def ev: ClassTag[T]
  def size: Int
  lazy val array = Array.fill[T](size)(null.asInstanceOf[T]) 
}

case class HasStringArray(size: Int)(implicit val ev: ClassTag[String]) extends HasArray[String]

scala> HasStringArray(8).array
res11: Array[String] = Array(null, null, null, null, null, null, null, null)

【讨论】:

  • T 上应该有一个下限 - trait THasArray[T >: Null] - 然后你就不需要演员表了。
  • 我认为Null 下限实际上不会起作用。有 attempt 在类型级别避免 null,但现在它似乎被放弃了。
  • Null 类型仍然存在。这不是试图避免 null;相反,它会将 null 带入类型系统。
  • 我试过不用lazy,效果也不错,为什么要懒惰地创建数组呢?至于下限:如果没有下限,我设法得到一个HasArray[Int],它可以工作。否则下限会阻止这一点。
  • @Beryllium without lazy 如果您忘记 early initialize val 使用的字段,则会导致 NPE:new HasArray[Int] { val ev = implicitly[ClassTag[Int]]; val size = 4 }
猜你喜欢
  • 2019-04-19
  • 1970-01-01
  • 2016-07-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-14
  • 1970-01-01
  • 1970-01-01
  • 2012-12-11
相关资源
最近更新 更多