17

我在一些单元测试代码中发现了一些令人困惑的 trait 用法,例如:

trait MyTrait {
  val t1 = ... //some expression
  val t2 = ... //some expression
}

然后使用 new 实例化特征,同时在实例化之后用花括号包裹的一些表达式。

test("it is a test") {
  new MyTrait {
    // do something with t1 and t2
  }
}

我对这种奇怪的语法感到困惑。

我的问题是:

  1. 为什么使用花括号跟随特征实例化?

  2. 在这种情况下特征实例化的目的是什么,其他情况也可能有帮助?

4

4 回答 4

42

您没有实例化特征:特征本身无法实例化;只有非抽象类可以。您在这里所做的是使用 Scala 的简写来定义扩展特征的匿名/无名类并在同一语句中实例化它。

val anonClassMixingInTrait = new MyTrait {
  def aFunctionInMyClass = "I'm a func in an anonymous class"
}

相当于:

class MyClass extends MyTrait {
  def aFunctionInMyClass = "I'm a func in a named class"
}

val namedClassMixingInTrait = new MyClass

不同之处在于您只能在定义时实例化该匿名类,因为它没有名称,也没有构造函数参数。

于 2013-04-28T04:51:27.167 回答
10

Steve Buzzard 已经解释过,什么是匿名类,但你也问了目的。这里的目的是,在测试中你经常有一些默认值,你想在每个测试中使用。有时你也有状态,可能会被一些测试改变。要始终从正确的值开始(测试也可以并行运行),您可以将它们封装在这些匿名实例中。此匿名实例中的代码是构造函数,将在实例化时对其进行评估,从而执行您的测试。

于 2013-04-28T07:40:44.123 回答
4
val t = new MyTrait {
  val t1 = ... //some expression
  val t2 = ... //some expression
}

是相同的

val t = new AnyRef with MyTrait {
  val t1 = ... //some expression
  val t2 = ... //some expression
}

是相同的

val t = new Object with MyTrait {
  val t1 = ... //some expression
  val t2 = ... //some expression
}
于 2013-04-29T14:56:03.290 回答
0

示例来自李浩毅的“Hands on Scala”。第 5 章。

trait StrParser[T]{ def parse(s: String): T }
object StrParser{
  implicit object ParseInt extends StrParser[Int]{
    def parse(s: String) = s.toInt
  }
  implicit object ParseBoolean extends StrParser[Boolean]{
    def parse(s: String) = s.toBoolean
  }
  implicit object ParseDouble extends StrParser[Double]{
    def parse(s: String) = s.toDouble
  }
}

def parseFromString[T](s: String)(implicit parser: StrParser[T]) = {
  parser.parse(s)
}

implicit def ParseSeq[T](implicit p: StrParser[T]) = new StrParser[Seq[T]]{
  def parse(s: String) = s.split(',').toSeq.map(p.parse)
}

parseFromString[Seq[Int]]("1,2,3")

ParseSeq 是类型为 Seq[T] 和隐式参数 p:StrParser[T] 的 StrParser 的构造函数。

还有一个用于类型 [T, V] 的 StrParser 构造函数

implicit def ParseTuple[T, V](implicit p1: StrParser[T], p2: StrParser[V]) =
  new StrParser[(T, V)]{
    def parse(s: String) = {
      val Array(left, right) = s.split('=')
      (p1.parse(left), p2.parse(right))
    }
  }

现在我们可以制作

parseFromString[Seq[(Int, Boolean)]]("1=true,2=false,3=true,4=false")

结果是 Seq[(Int, Boolean)] = ArraySeq((1,true), (2,false), (3,true), (4,false))

于 2022-01-19T10:16:58.783 回答