假设我们有这样一个类:
import java.net.URL
import xml._
class SearchData(xml: Node) {
def this(url: URL) = this (XML.load(url))
}
我们想在调用this (XML.load(url))
之前执行一些代码 - 比如用try
测试一下。人们会期望写这样的东西会起作用:
class SearchData(xml: Node) {
def this(url: URL) {
try {
this (XML.load(url))
} catch {
case _ => this(<results/>)
}
}
}
但它不会,因为Scala要求您在重载的构造函数中调用this()
第一个语句,在这种情况下try
成为第一个语句。
那么这个问题的解决方案是什么?
答案 0 :(得分:6)
def this(url: Url) = this(try {XML.load(url)} catch {case _ => <results/>})
更一般地说,参数的评估必须在构造函数调用之前进行,所以你在那里做( scala中的块是表达式,但写一个例程,通常写在同伴中对象,如果它太长了)。你不能做的是让这段代码选择你调用的其他构造函数。但是,由于他们所有人必须前往主要人员,所以你不会损失太多。此外,您需要调用的其他构造函数至少有一个参数。如果有几个构造函数,那么主要的构造函数通常不应该是没有参数的构造函数(参见Scala problem optional constructor)
答案 1 :(得分:5)
伴侣对象中的工厂方法:
object SearchData {
def apply(xml: Node) = new SearchData(xml) //Added to provide uniform factories
def apply(url: URL) = {
try {
new SearchData(XML.load(url))
} catch {
case _ => new SearchData(<results/>)
}
}
}
//Example
val sd = SearchData( new URL( "http://example.com/" ) )
不仅可以简化设计,还可以使用new
关键字。
答案 2 :(得分:3)
虽然didierd的解决方案解决了声明的问题,并且与此问题有些接近,但在调用this
之前必须执行多个语句时仍然无法解决问题。这个方案为所有场景提供了一般方法:
class SearchData(xml: Node) {
def this(url: URL) = this {
println(url)
try {
XML.load(url)
} catch {
case _ => <results/>
}
}
}
这里的诀窍是this
被赋予执行匿名函数的结果,在该体中你可以做任何事情。
但这仅在您拥有单参数主构造函数时才有效 - 在其他情况下,您将不得不引入基于Tuple
的解决方法:
class SearchData(xml: Node, valid: Boolean) {
def this(url: URL) = this {
println(url)
try {
(XML.load(url), true)
} catch {
case _ => (<results/>, false)
}
}
def this(t: (Node, Boolean)) = this(t._1, t._2)
}