繁体   English   中英

如何获取Scala中类型的默认值?

[英]How can I obtain the default value for a type in Scala?

我正在尝试编写一个Scala函数,它返回一个类型的默认值(0,0.0,false,'\\ 0'等,对于值类型,null为引用类型)。 我想出了这个:

def defaultValue[U]: U = {
  class Default[U] { var default: U = _ }
  new Default[U].default
}

虽然直接调用它的效果很好,但是当通过本身是通用的函数调用时,它甚至对值类型也返回null,如此REPL会话所示:

Welcome to Scala version 2.8.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_24).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def defaultValue[U]: U = { class Default[U] {var default: U = _ }; new Default[U].default }
defaultValue: [U]U

scala> defaultValue[Boolean] // direct call works
res0: Boolean = false

scala> var res: Any = 0
res: Any = 0

scala> def setRes[U] = { res = defaultValue[U]; defaultValue[U] }
setRes: [U]U

scala> setRes[Boolean] // returns a Boolean, but...
res1: Boolean = false

scala> res
res2: Any = null // ... sets the res variable to null.

有人可以向我解释一下:

  1. 为什么会发生这种情况(以及为什么编译器/解释器在没有足够的信息返回真正的布尔值时不会抱怨);
  2. 我该怎么办呢?

以下是您问题的更精简版本:

scala> defaultValue[Boolean]: Any
res0: Any = null

scala> defaultValue[Boolean]: Boolean
res1: Boolean = false

当你调用res = defaultValue[U]时,第一个版本是适用的,因为即使U是Boolean类型, res也是Any类型

如果使用-Xprint:all选项编译这个小程序

object Test {
  def defaultValue[U]: U = { class Default[U] {var default: U = _ }; new Default[U].default }

  def main(args:Array[String]) {
    val any = defaultValue[Boolean]: Any
    println(any)
    val bool = defaultValue[Boolean]: Boolean
    println(bool)
  }
}

你会在擦除阶段之前看到,你有:

val any: Any = (Test.this.defaultValue[Boolean](): Any);
scala.this.Predef.println(any);
val bool: Boolean = (Test.this.defaultValue[Boolean](): Boolean);
scala.this.Predef.println(bool)

然后在擦除阶段结束时:

val any: java.lang.Object = (Test.this.defaultValue(): java.lang.Object);
scala.this.Predef.println(any);
val bool: Boolean = (scala.Boolean.unbox(Test.this.defaultValue()): Boolean);
scala.this.Predef.println(scala.Boolean.box(bool))

所以会发生的情况是,在两种情况下,引擎盖下的defaultValue[Boolean]返回null,但是当返回类型是布尔值时,null会被解除为false。 您可以在REPL中验证:

scala> Boolean.unbox(null)
res0: Boolean = false

scala> null.asInstanceOf[Boolean]
res1: Boolean = false

编辑:我有一个想法 - 不是我推荐它。 不确定你的用例是什么( res = false对我来说更容易..)

scala> def f[@specialized U] = { class X { var x: U = _ }; (new X).x }
f: [U]U

scala> var res: Any = _
res: Any = null

scala> def g[@specialized U] = { res = f[U]; f[U] }
g: [U]U

scala> g[Boolean]
res0: Boolean = false

scala> res
res1: Any = false

为了记录,这里是我发现的唯一可靠的工作。 欢迎改进。

def defaultValue[T: ClassManifest]: T = classManifest[T].erasure.toString match {
  case "void" => ().asInstanceOf[T]
  case "boolean" => false.asInstanceOf[T]
  case "byte" => (0: Byte).asInstanceOf[T]
  case "short" => (0: Short).asInstanceOf[T]
  case "char" => '\0'.asInstanceOf[T]
  case "int" => 0.asInstanceOf[T]
  case "long" => 0L.asInstanceOf[T]
  case "float" => 0.0F.asInstanceOf[T]
  case "double" => 0.0.asInstanceOf[T]
  case _ => null.asInstanceOf[T]
}

我知道即使T <: NotNull ,我也会得到null,这是一个问题。 然后,对于NotNull子类,使用_初始化变量存在问题。

您可以创建自己的Default 类型来处理此问题。 这是代码的样子。 我为scala集合添加了特殊处理,它返回一个空集合而不是null。

import scala.collection.immutable

class Default[+A](val default: A)

trait LowerPriorityImplicits {
  // Stop AnyRefs from clashing with AnyVals
  implicit def defaultNull[A <: AnyRef]:Default[A] = new Default[A](null.asInstanceOf[A])  
}

object Default extends LowerPriorityImplicits {
  implicit object DefaultDouble extends Default[Double](0.0)
  implicit object DefaultFloat extends Default[Float](0.0F)
  implicit object DefaultInt extends Default[Int](0)
  implicit object DefaultLong extends Default[Long](0L)
  implicit object DefaultShort extends Default[Short](0)
  implicit object DefaultByte extends Default[Byte](0)
  implicit object DefaultChar extends Default[Char]('\u0000')
  implicit object DefaultBoolean extends Default[Boolean](false)
  implicit object DefaultUnit extends Default[Unit](())

  implicit def defaultSeq[A]: Default[immutable.Seq[A]] = new Default[immutable.Seq[A]](immutable.Seq())
  implicit def defaultSet[A]: Default[Set[A]] = new Default[Set[A]](Set())
  implicit def defaultMap[A, B]: Default[Map[A, B]] = new Default[Map[A, B]](Map[A, B]())
  implicit def defaultOption[A]: Default[Option[A]] = new Default[Option[A]](None)

  def value[A](implicit value: Default[A]): A = value.default
}

这些是在repl中使用它的结果。 请注意,可以通过创建新的隐式Default[String]来覆盖String的默认值。

scala> Default.value[Int]
res0: Int = 0

scala> Default.value[Boolean]
res1: Boolean = false

scala> Default.value[String]
res2: String = null

scala> Default.value[Set[Int]]
res3: Set[Int] = Set()

scala> Default.value[immutable.Seq[Int]]
res4: scala.collection.immutable.Seq[Int] = List()

scala> Default.value[String]
res5: String = null

scala> Default.value[AnyRef]
res6: AnyRef = null

scala> implicit val emptyStringAsDefault:Default[String] = new Default[String]("")
emptyStringAsDefault: Default[String] = Default@7d78d7b4

scala> Default.value[String]
res7: String = ""

我知道已经有了“最佳答案”,但真的很简单:

def defaultValue[U: ClassManifest]: U = new Array[U](1)(0)

它似乎工作,虽然由于创建一个临时数组对象有点昂贵。 有没有人知道它给出错误值的任何情况?

我一直在寻找一个“更便宜”的选择,但这个问题告诉我可能没有。

我写了一篇关于为Scala构建默认机制的博客文章。 你可以在这里找到它。

如果你不希望Option[_]默认为NoneString to ""等然后从对象Default删除相应的implicits。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM