最初のオプションは最も効率的なオプションですが、もう 1 つのオプションはコードを関数オブジェクトにラップすることによってオーバーヘッドを導入します。しかし、そのようなラッパーを作成することは確かに可能です。定義しましょう
trait Chainable {
final def mkChain(f: () => Any): () => this.type =
() => { f(); this; }
final def mkChain[A](f: (A) => Any): (A) => this.type =
(x: A) => { f(x); this; }
final def mkChain[A,B](f: (A,B) => Any): (A,B) => this.type =
(x: A, y: B) => { f(x, y); this; }
// etc. for other arities
}
注意this.type
してください、関数の結果は、関数が定義されているクラスの型であると書かれています。
class MyClass extends Chainable {
val methodTwo =
mkChain((x: Any, y: String) => println("Doing something " + y));
}
の結果はmethodTwo
になりますMyClass
。
更新:暗黙的な変換を使用する別のオプションがあります。
trait ToChain {
implicit class AsThis(val _underlying: Any) {
def chain: ToChain.this.type = ToChain.this
}
}
class MyClass2 extends ToChain {
def methodOne(arg1: Any): Unit =
println("Doing something")
def methodTwo(arg1: String): Unit =
println("Doing something else " + arg1)
methodOne(3).chain.methodTwo("x");
}
を呼び出すchain
と、何でも に変換されthis.type
ます。ただし、クラス内でのみ機能し、new MyClass2.methodOne(3).chain.methodTwo("x")
外部のようなものを呼び出すことはできません。
更新:Unit
からへの暗黙的な変換に基づくさらに別のソリューションthis
:
import scala.language.implicitConversions
class Chain[A](val x: A) {
implicit def unitToThis(unit: Unit): A = x;
}
implicit def unchain[A](c: Chain[A]): A = c.x;
// Usage:
val r: MyClass = new Chain(new MyClass) {
x.methodOne(1).methodTwo(2,3);
}