特征参数
Scala 3 允许特征具有参数,就像类具有参数一样。
trait Greeting(val name: String):
def msg = s"How are you, $name"
class C extends Greeting("Bob"):
println(msg)
在初始化特征之前立即计算特征的参数。
特征参数的一个潜在问题是如何防止歧义。例如,您可能尝试使用不同的参数扩展 Greeting
两次。
class D extends C, Greeting("Bill") // error: parameter passed twice
这应该打印“Bob”还是“Bill”?事实上,此程序是非法的,因为它违反了以下特征参数的第二个规则
-
如果类
C
扩展了参数化特征T
,并且其超类没有扩展,则C
必须 向T
传递参数。 -
如果类
C
扩展了参数化特征T
,并且其超类也扩展了,则C
不能 向T
传递参数。 -
特征绝不能向父特征传递参数。
这是一个扩展参数化特征 Greeting
的特征。
trait FormalGreeting extends Greeting:
override def msg = s"How do you do, $name"
根据要求,不会向 Greeting
传递任何参数。然而,在定义一个扩展 FormalGreeting
的类时,这会带来一个问题
class E extends FormalGreeting // error: missing arguments for `Greeting`.
编写 E
的正确方法是同时扩展 Greeting
和 FormalGreeting
(顺序不限)
class E extends Greeting("Bob"), FormalGreeting
具有上下文参数的特征
如果缺失的特征仅包含 上下文参数,则会放宽此“需要显式扩展”规则。在这种情况下,特征引用会作为具有推断参数的附加父级隐式插入。例如,下面是问候语的一个变体,其中收件人是类型为 ImpliedName
的上下文参数
case class ImpliedName(name: String):
override def toString = name
trait ImpliedGreeting(using val iname: ImpliedName):
def msg = s"How are you, $iname"
trait ImpliedFormalGreeting extends ImpliedGreeting:
override def msg = s"How do you do, $iname"
class F(using iname: ImpliedName) extends ImpliedFormalGreeting
最后一行中 F
的定义会隐式扩展为
class F(using iname: ImpliedName) extends
Object,
ImpliedGreeting(using iname),
ImpliedFormalGreeting
请注意插入的超级特征 ImpliedGreeting
的引用,该引用未明确提及。
参考
有关更多信息,请参阅 Scala SIP 25。
本文