Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 如何在Scala中获取类型的默认值?_Generics_Scala_Null_Default Value - Fatal编程技术网

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

Generics 如何在Scala中获取类型的默认值?,generics,scala,null,default-value,Generics,Scala,Null,Default Value,我正在尝试编写一个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 versi

我正在尝试编写一个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.
谁能给我解释一下:

  • 为什么会发生这种情况(如果没有足够的信息返回一个真正的布尔值,为什么编译器/解释器不会抱怨);及
  • 我怎么能修好它

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

    scala> defaultValue[Boolean]: Any
    res0: Any = null
    
    scala> defaultValue[Boolean]: Boolean
    res1: Boolean = false
    
    当您调用
    res=defaultValue[U]
    时,第一个版本适用,因为即使
    U
    是布尔类型,
    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,但当返回类型为Boolean时,null被取消绑定为false。您可以在REPL中验证:

    scala> Boolean.unbox(null)
    res0: Boolean = false
    
    scala> null.asInstanceOf[Boolean]
    res1: Boolean = false
    
    编辑:我有一个想法——我不是在推荐它。不确定您的用例是什么(
    res=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我知道已经有了“最佳答案”,我也会得到空值,但真正简单的是:

    def defaultValue[U: ClassManifest]: U = new Array[U](1)(0)
    
    虽然由于创建临时数组对象而有些昂贵,但它似乎可以工作。有人知道它给出错误值的情况吗


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

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


    如果不希望
    选项[\u]
    默认为
    字符串
    默认为
    等,则从对象
    默认值

    中删除相应的隐式。您可以创建自己的
    默认值
    来处理此问题。下面是代码的样子。我为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
    }
    

    我已经找到了一种使用类清单和匹配擦除的方法,但它看起来并不漂亮。谁想打赌原因不是类型擦除?无论如何,既然您只有有限多个已知的期望行为,为什么不硬编码呢?丑陋,是的,但可能是最有效的。谢谢,这是一个很好的解释为什么。现在为什么编译器不能在编译时告诉我更多?比如,听着,伙计,你想要一个布尔值,但是我可以给你空值,对不起?不确定除了你的用例之外还有其他的
    def[T]:T
    用例。如果没有任何传递的参数,很难实现T。所以可能没有警告,因为从来没有人想过这样做。@specialized技巧很好,但很危险,因为一旦你从一个非专门化的上下文中包装对f的调用,它就会崩溃。这可能会导致难以追踪的bug。因此,只需调用null.asInstanceOf[B]就可以很好地完成这项工作。
    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
    }
    
    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 = ""