如果存在现有的Java类pkg.Test,
package pkg;
public class Test {
public int v;
public Test(int v) { this.v = v; }
}
尝试通过定义scala伴随对象
来创建提取器package pkg
object Test{
def unapply(t : Test) : Option[Int] = Some(t.v)
}
产生错误“测试已被定义为对象测试”。 但是,如果我在新包中创建java类的同义词
,一切似乎都有效package pkg
package object matchers {
type Test = pkg.Test
}
并在新包中定义相应的对象
package pkg.matchers
object Test {
def unapply(t : Test) : Option[Int] = Some(t.v)
}
现在,新包中的模式和原始类的所有成员都可用
import pkg.matchers._
object main {
def main(args : Array[String]) {
val t = new Test(1)
t match {case Test(v) => println(v)}
println(t.v)
}
}
添加类型同义词似乎很奇怪。除了必须使用新包之外,以这种方式添加模式匹配是否有任何问题?有没有办法在原始包装中提供提取器?
答案 0 :(得分:4)
这是因为在与Java库交互时,Scala需要一种方法将Java的静态方法映射到Scala的单例对象。
例如,如果您有以下Java类:
package pkg;
class Test {
public static void printHello() {
System.out.println("Hello");
}
}
我们如何在Scala中调用printHello
?它将如下所示:
import pkg.Test
Test.printHello()
如您所见,语法与调用object Test
中的方法完全相同。从这一点来看,已经定义了Test
单例,并且您无法定义具有相同FQN两次的object
。
这就是为什么你需要定义pkg.matchers.Test
所以它不会与pkg.Test
冲突。
Scala的编译器非常聪明,可以发现pkg.matchers.Test
是一个无法使用new
关键字构造它的单例,因此当您编写new Test(1)
时,它是{{1}而不是pkg.Test
。这就是您可以在代码示例中同时使用它们的原因。
事实上,您根本不需要pkg.matchers.Test
,以下工作正常:
type Test = pkg.Test
Extractor不需要是伴随对象,这意味着您不需要相应的类。任何package pkg
package matchers {
object Test {
def unapply(t : Test) : Option[Int] = Some(t.v)
}
}
object main {
import pkg.matchers._
def main(args : Array[String]) {
val t = new Test(1)
t match {case Test(v) => println(v)}
println(t.v)
}
}
object
方法都可以作为提取器使用。
unapply
因此,如果主要方法不在object StringLength {
def unapply(x: String): Option[Int] = Some(x.length)
}
object Main {
def main(args: Array[String]) {
"Hello World" match {
case StringLength(x) => println("length:" + x)
}
}
}
中,您有以下选择:
将提取器重命名为其他名称,因此编译器可以知道您正在使用提取器。
使用FQN,因此编译器知道您是pkg
而不是pkg.matchers.Test
。
pkg.Test
使用package pkg.matchers {
import pkg._
object Test {
def unapply(t : Test) : Option[Int] = Some(t.v)
}
}
object Main {
def main(args: Array[String]) {
import pkg.Test
val t = new Test(1)
t match {case pkg.matchers.Test(v) => println(v)}
println(t.v)
}
}
语法将pkg.Test
重命名为其他名称,因此不会与import
冲突。
pkg.matchers.Test
只需导入object Main {
def main(args: Array[String]) {
import pkg.{Test => JTest}
import pkg.matchers.Test
val t = new JTest(1)
t match {case Test(v) => println(v)}
println(t.v)
}
}
的所有内容,并专门导入pkg
。
pkg.matcher.Test