如何获取 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.
有人可以向我解释一下:
- 为什么会发生这种情况(以及为什么编译器/解释器在没有足够的信息返回真布尔值时不会抱怨); 我该如何
- 解决它?
I'm trying to write a Scala function that returns the default value of a type (0, 0.0, false, '\0', etc. for value types and null for reference types). I came up with this:
def defaultValue[U]: U = {
class Default[U] { var default: U = _ }
new Default[U].default
}
and while this works well if called directly, it returns null even for value types when called through a function that itself is generic, as shown in this REPL session:
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.
Can someone explain to me:
- why this happens (and why the compiler/interpreter doesn't complain if there is not enough information for it to return a true Boolean); and
- how I can fix it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是您的问题的更精简版本:
第一个版本是您调用
res = defaultValue[U]
时应用的版本,因为即使U
是布尔类型,res
的类型为 Any如果您使用
-Xprint:all
选项编译这个小程序,您将看到在擦除阶段之前,您有:
然后在擦除阶段结束时:
因此,在这两种情况下,
defaultValue[Boolean]
在幕后都会返回 null,但当返回类型为 Boolean 时,null 会被拆箱为 false。您可以在 REPL 中验证这一点:编辑:我有一个想法 - 并不是我推荐它。不确定您的用例是什么(
res = false
对我来说似乎更容易..)Here is a more condensed version of your issue:
The first version is what applies when you call
res = defaultValue[U]
because even thoughU
is of type Boolean,res
is of type AnyIf you compile this little program using the
-Xprint:all
optionYou'll see that right before the erasure phase, you have:
Then at the end of the erasure phase:
So what happens is that under the hood
defaultValue[Boolean]
returns null in both cases, but then null is unboxed into false when the return type is a Boolean. You can verify that in the REPL:Edit: I had an idea - not that I'm recommending it. Not sure what your use case is (
res = false
seems easier to me..)您可以创建自己的
默认
type-class 来处理这个问题。代码如下所示。我为 scala 集合添加了特殊处理,返回空集合而不是 null。这些是在 repl 中使用它的结果。请注意,可以通过创建新的隐式
Default[String]
来覆盖String
的默认值。You can create your own
Default
type-class to handle this. Here is what the code looks like. I added special handling for scala collections that returns an empty collection instead of null.These are the results of using this in the repl. Notice that the default value for
String
can be overriden by creating a new implicitDefault[String]
.作为记录,这是我发现的唯一可以使这项工作可靠的方法。欢迎改进。
我知道即使
T <: NotNull
我也会得到 null,这是一个问题。然而,对于NotNull
子类来说,使用_
初始化变量存在问题。For the record, here's the only I've found (yet) to make this work reliably. Improvements are welcome.
I'm aware that I get null even if
T <: NotNull
, which is a problem. Then again, there is a problem with initialization of vars with_
forNotNull
subclasses.我知道已经有了“最佳答案”,但是真正简单的呢:
它似乎有效,尽管由于创建临时数组对象而有点昂贵。有谁知道它给出错误值的情况吗?
我一直在寻找一种“更便宜”的替代方案,但这个问题告诉我可能没有。
I know there is already "best answer", but what about the really simple:
It seems to work, although it's somewhat expensive due to creating a temporary array object. Does anyone know of any cases where it gives the wrong value?
I was looking for a "cheaper" alternative, but this question tells me there probably isn't one.
我写了一篇关于为 Scala 构建默认机制的博客文章。您可以在此处找到它。
如果您不希望
Option[_]
默认为None
、String
为""
等,则摆脱来自对象Default
的相应隐式。I have written a blog post on building a defaulting mechanism for Scala. You can find it here.
If you do not want
Option[_]
to default toNone
,String
to""
etc then get rid of the respective implicits from the objectDefault
.