如何声明单一方法特征

How to declare a one-method trait

在 scala 中,有多种方法可以仅用一种方法声明特征

trait OneMethod extends (A => B)

trait OneMethod {
  def myMethod(a: A) : B
}

每种解决方案的优缺点是什么?

通过扩展 (A => B),您是说 OneMethod 是一个函数,可以直接使用:

trait TraitA extends (Int => String)
class ClassA extends TraitA { def apply(i: Int) = i.toString }

val a = new ClassA
(1 to 5).map(a)      // IndexedSeq[String] = Vector(1, 2, 3, 4, 5)

如果你不扩展 (A => B),你就做不到;相反,您必须明确地告诉它方法名称是什么:

trait TraitB { def myMethod(i: Int): String }
class ClassB extends TraitB { def myMethod(i: Int) = i.toString }

val b = new ClassB
(1 to 5).map(b)              // error, required: Int => ?
(1 to 5).map(b.myMethod)     // IndexedSeq[String] = Vector(1, 2, 3, 4, 5)

因此:扩展 (A => B) 使您的 class 在使用上更灵活一些,并且不那么冗长。另一方面,如果你想要一个比 apply 更具描述性的名称,你可以做版本 B.

同样值得注意的是:两个版本都没有将 trait 限制为只有一种方法;您可以向其中任何一个添加额外的方法。

您可以使用以下方法获得两种解决方案的优点:

trait Transformer[A, B] extends (A => B) {
  override def apply(a: A): B = transform(a)
  def transform(a: A): B
}

object FooTransformer extends Transformer[String, String] {
  override def transform(a: String): String = a + ", world"
}

val transformer = FooTransformer

// "classic" usage
val foo = "hello"
// "hello, world"
val transformedFoo = transformer.transform(foo) 

// functional usage
val fooList = List("foo", "bar", "baz")
// List("foo, world", "bar, world", "baz, world")
val transformedFooList = fooList map transformer 

这为您提供了灵活性和描述性,因为您既可以将其用作函数,也可以经典 方式使用。