如何向库对象添加新方法?

时间:2013-06-12 17:59:45

标签: scala enrich-my-library

我有一个来自图书馆的课程(具体来说,com.twitter.finagle.mdns.MDNSResolver)。我想扩展该类(我希望它返回Future [Set],而不是Try [Group])。

我知道,当然,我可以对它进行子类化并在那里添加我的方法。但是,我正在尝试学习Scala,这似乎是尝试新事物的机会。

我认为可能的原因是JavaConverters的行为。以下代码:

class Test {
    var lst:Buffer[Nothing] = (new java.util.ArrayList()).asScala
}

无法编译,因为Java asScala上没有ArrayList方法。但是如果我导入一些新的定义:

class Test {
    import collection.JavaConverters._
    var lst:Buffer[Nothing] = (new java.util.ArrayList()).asScala
}

然后突然 一个asScala方法。所以看起来ArrayList类正在透明地扩展。

我是否正确理解JavaConverters的行为?我可以(并且应该)复制该方法吗?

3 个答案:

答案 0 :(得分:8)

Scala支持一种称为隐式转换的东西。请看以下内容:

val x: Int = 1
val y: String = x

第二项作业不起作用,因为需要String,但找到了Int。但是,如果您将以下内容添加到范围内(仅限于范围内,可以来自任何地方),则可以:

implicit def int2String(x: Int): String = "asdf"

请注意,方法的名称无关紧要。

通常做什么,被称为pimp-my-library-pattern:

class BetterFoo(x: Foo) {
  def coolMethod() = { ... }
}

implicit def foo2Better(x: Foo) = new BetterFoo(x)

这样,您就可以在coolMethod上致电Foo了。这经常被使用,因为从Scala 2.10开始,你可以写:

implicit class BetterFoo(x: Foo) {
  def coolMethod() = { ... }
}

做同样的事情,但显然更短更好。

所以你可以这样做:

implicit class MyMDNSResolver(x: com.twitter.finagle.mdns.MDNSResolver) = {
  def awesomeMethod = { ... }
}

如果awesomeMethod在范围内,您就可以在任何MDNSResolver上致电MyMDNSResolver

答案 1 :(得分:2)

执行此操作的方法是使用隐式转换。这些可用于定义views,它们用于丰富现有库的用法称为“pimp my library”。

我不确定您是否需要编写从Try[Group]Future[Set]的转换,或者您可以从TryFutureGroup写一个转换。 1}}到Set,让他们撰写。

答案 2 :(得分:2)

这是使用隐式转换实现的;此功能允许您在调用无法识别的方法时自动将一种类型转换为另一种类型。

在2006年Martin Odersky撰写的一篇文章之后,您所描述的模式被称为“丰富我的图书馆”。对于您想要做的事情,这仍然是一个很好的介绍:http://www.artima.com/weblogs/viewpost.jsp?thread=179766