特征可以在 Scala 3 中有辅助构造函数吗?
Can traits have secondary constructors in Scala 3?
我从 Auxiliary Class Constructors 文章中复制了以下代码,粘贴到 Scastie 中,将 class
更改为 trait
并将 Scala 版本设置为 3.1.0:
val DefaultCrustSize = 12
val DefaultCrustType = "THIN"
// the primary constructor
trait Pizza (var crustSize: Int, var crustType: String) {
// one-arg auxiliary constructor
def this(crustSize: Int) = {
this(crustSize, DefaultCrustType)
}
// one-arg auxiliary constructor
def this(crustType: String) = {
this(DefaultCrustSize, crustType)
}
// zero-arg auxiliary constructor
def this() = {
this(DefaultCrustSize, DefaultCrustType)
}
override def toString = s"A $crustSize inch pizza with a $crustType crust"
}
Here's the result. 它给出了以下错误:
org.scalameta.invariants.InvariantFailedException: invariant failed:
when verifying scala.meta.classifiers.`package`.XtensionClassifiable[scala.meta.Template](templ)(scala.meta.Tree.classifiable[scala.meta.Template]).is[Template.Quasi](Template.this.Quasi.ClassifierClass[scala.meta.Template]).||(templ.stats.forall(((x: scala.meta.Stat) => scala.meta.classifiers.`package`.XtensionClassifiable[scala.meta.Stat](x)(scala.meta.Tree.classifiable[scala.meta.Stat]).is[Ctor](scala.meta.Ctor.ClassifierClass[scala.meta.Stat]).`unary_!`)))
found that scala.meta.classifiers.`package`.XtensionClassifiable[scala.meta.Template](templ)(scala.meta.Tree.classifiable[scala.meta.Template]).is[Template.Quasi](Template.this.Quasi.ClassifierClass[scala.meta.Template]) is false
and also templ.stats.forall(((x: scala.meta.Stat) => scala.meta.classifiers.`package`.XtensionClassifiable[scala.meta.Stat](x)(scala.meta.Tree.classifiable[scala.meta.Stat]).is[Ctor](scala.meta.Ctor.ClassifierClass[scala.meta.Stat]).`unary_!`)) is false
where Template = scala.meta.Template$@7759c8f1
where templ = {
// one-arg auxiliary constructor
def this(crustSize: Int) = {
this(crustSize, DefaultCrustType)
}
// one-arg auxiliary constructor
def this(crustType: String) = {
this(DefaultCrustSize, crustType)
}
// zero-arg auxiliary constructor
def this() = {
this(DefaultCrustSize, DefaultCrustType)
}
override def toString = s"A $crustSize inch pizza with a $crustType crust"
}
at org.scalameta.invariants.InvariantFailedException$.raise(Exceptions.scala:19)
at scala.meta.Defn$Trait$.internal7(Trees.scala:432)
at scala.meta.Defn$Trait$.apply(Trees.scala:425)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$traitDef(ScalametaParser.scala:4592)
at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:888)
at scala.meta.internal.parsers.ScalametaParser.traitDef(ScalametaParser.scala:4570)
at scala.meta.internal.parsers.ScalametaParser.tmplDef(ScalametaParser.scala:4548)
at scala.meta.internal.parsers.ScalametaParser.defOrDclOrSecondaryCtor(ScalametaParser.scala:4201)
at scala.meta.internal.parsers.ScalametaParser.nonLocalDefOrDcl(ScalametaParser.scala:4172)
at scala.meta.internal.parsers.ScalametaParser$$anonfun$templateStat.applyOrElse(ScalametaParser.scala:5120)
at scala.meta.internal.parsers.ScalametaParser$$anonfun$templateStat.applyOrElse(ScalametaParser.scala:5114)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:35)
at scala.meta.internal.parsers.ScalametaParser.statSeq(ScalametaParser.scala:5057)
at scala.meta.internal.parsers.ScalametaParser.templateStats(ScalametaParser.scala:5130)
at scala.meta.internal.parsers.ScalametaParser.templateStatSeq(ScalametaParser.scala:5110)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$templateBody(ScalametaParser.scala:4945)
at scala.meta.internal.parsers.ScalametaParser.inBraces(ScalametaParser.scala:800)
at scala.meta.internal.parsers.ScalametaParser.templateBody(ScalametaParser.scala:4945)
at scala.meta.internal.parsers.ScalametaParser.templateBodyOpt(ScalametaParser.scala:4953)
at scala.meta.internal.parsers.ScalametaParser.template(ScalametaParser.scala:4887)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$template(ScalametaParser.scala:4906)
at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:888)
at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:922)
at scala.meta.internal.parsers.ScalametaParser.template(ScalametaParser.scala:4891)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$templateOpt(ScalametaParser.scala:4931)
at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:888)
at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:922)
at scala.meta.internal.parsers.ScalametaParser.templateOpt(ScalametaParser.scala:4923)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$objectDef(ScalametaParser.scala:4682)
at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:888)
at scala.meta.internal.parsers.ScalametaParser.objectDef(ScalametaParser.scala:4674)
at scala.meta.internal.parsers.ScalametaParser.tmplDef(ScalametaParser.scala:4558)
at scala.meta.internal.parsers.ScalametaParser.topLevelTmplDef(ScalametaParser.scala:4540)
at scala.meta.internal.parsers.ScalametaParser$$anonfun$topStat.applyOrElse(ScalametaParser.scala:5079)
at scala.meta.internal.parsers.ScalametaParser$$anonfun$topStat.applyOrElse(ScalametaParser.scala:5067)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:35)
at scala.meta.internal.parsers.ScalametaParser.statSeq(ScalametaParser.scala:5057)
at scala.meta.internal.parsers.ScalametaParser.topStatSeq(ScalametaParser.scala:5066)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$batchSource(ScalametaParser.scala:5297)
at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:888)
at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:922)
at scala.meta.internal.parsers.ScalametaParser.batchSource(ScalametaParser.scala:5256)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$source(ScalametaParser.scala:5239)
at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:888)
at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:922)
at scala.meta.internal.parsers.ScalametaParser.source(ScalametaParser.scala:5238)
at scala.meta.internal.parsers.ScalametaParser.entrypointSource(ScalametaParser.scala:5244)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$parseSource(ScalametaParser.scala:143)
at scala.meta.internal.parsers.ScalametaParser.parseRule(ScalametaParser.scala:53)
at scala.meta.internal.parsers.ScalametaParser.parseSource(ScalametaParser.scala:143)
at scala.meta.parsers.Parse$.$anonfun$parseSource(Parse.scala:29)
at scala.meta.internal.parsers.ScalametaParser$$anon4.apply(ScalametaParser.scala:5308)
at scala.meta.parsers.Api$XtensionParseDialectInput.parse(Api.scala:25)
at scala.meta.parsers.Api$XtensionParseInputLike.parse(Api.scala:14)
at com.olegych.scastie.instrumentation.Instrument$.apply(Instrument.scala:199)
at com.olegych.scastie.instrumentation.InstrumentedInputs$.apply(InstrumentedInputs.scala:23)
at com.olegych.scastie.sbt.SbtProcess$$anonfun.applyOrElse(SbtProcess.scala:191)
at com.olegych.scastie.sbt.SbtProcess$$anonfun.applyOrElse(SbtProcess.scala:177)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:35)
at akka.actor.FSM.processEvent(FSM.scala:707)
at akka.actor.FSM.processEvent$(FSM.scala:704)
at com.olegych.scastie.sbt.SbtProcess.processEvent(SbtProcess.scala:64)
at akka.actor.FSM.akka$actor$FSM$$processMsg(FSM.scala:701)
at akka.actor.FSM$$anonfun$receive.applyOrElse(FSM.scala:695)
at akka.actor.Actor.aroundReceive(Actor.scala:539)
at akka.actor.Actor.aroundReceive$(Actor.scala:537)
at com.olegych.scastie.sbt.SbtProcess.aroundReceive(SbtProcess.scala:64)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:614)
at akka.actor.ActorCell.invoke(ActorCell.scala:583)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:268)
at akka.dispatch.Mailbox.run(Mailbox.scala:229)
at akka.dispatch.Mailbox.exec(Mailbox.scala:241)
at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
为什么?为什么它在第 1 行之后,看起来非常好并且在我删除其余部分时被接受? “不变失败”是否意味着它是编译器中的错误? (在这种情况下,许多其他编译器会在消息中添加鼓励报告的内容。)
主要问题:
- 特征中是否允许次要(或辅助 - IIUC 这两个术语我看到的显然可以互换表示相同)构造函数?
- 如果有,怎么称呼他们?
- 它们有什么用处(或者将会是,或者在实际拥有它们的另一种语言中)?
The documentation on trait
parameters只提到trait
参数,没有提到trait
构造函数:
Scala 3 allows traits to have parameters, just like classes have parameters.
它还链接到原始 SIP 文档以供参考:
For more information, see Scala SIP 25.
在 SIP-25 – trait
参数 中,它说 [粗体 强调我的]:
In the ClassDef
of traits, we still do not allow secondary constructors.
然而,这种限制并没有体现在 Syntax Summary 中,它实际上并没有在句法上区分 class
es 和 trait
s。因此,限制纯粹是文档之一,而不是语法规范。
所以,回答你的问题:
Why?
因为您的代码在语法上有效但在语义上无效,并且 ScalaMeta 似乎不期望这种特定类型的语义无效。
And why is it after line 1, which seems perfectly fine and gets accepted when I remove the rest? Does "invariant failed" mean that it's a bug in the compiler? (Many other compilers in such cases add to the message an encouragement to report it.)
这显然不是编译器中的错误,因为异常不是在编译器中抛出,而是在 ScalaMeta 中抛出。
Main questions:
- Are secondary (or auxiliary – IIUC the two terms I've seen used apparently interchangeably mean the same) constructors allowed in traits?
没有。 SIP-25 显然不允许它们。
我从 Auxiliary Class Constructors 文章中复制了以下代码,粘贴到 Scastie 中,将 class
更改为 trait
并将 Scala 版本设置为 3.1.0:
val DefaultCrustSize = 12
val DefaultCrustType = "THIN"
// the primary constructor
trait Pizza (var crustSize: Int, var crustType: String) {
// one-arg auxiliary constructor
def this(crustSize: Int) = {
this(crustSize, DefaultCrustType)
}
// one-arg auxiliary constructor
def this(crustType: String) = {
this(DefaultCrustSize, crustType)
}
// zero-arg auxiliary constructor
def this() = {
this(DefaultCrustSize, DefaultCrustType)
}
override def toString = s"A $crustSize inch pizza with a $crustType crust"
}
Here's the result. 它给出了以下错误:
org.scalameta.invariants.InvariantFailedException: invariant failed:
when verifying scala.meta.classifiers.`package`.XtensionClassifiable[scala.meta.Template](templ)(scala.meta.Tree.classifiable[scala.meta.Template]).is[Template.Quasi](Template.this.Quasi.ClassifierClass[scala.meta.Template]).||(templ.stats.forall(((x: scala.meta.Stat) => scala.meta.classifiers.`package`.XtensionClassifiable[scala.meta.Stat](x)(scala.meta.Tree.classifiable[scala.meta.Stat]).is[Ctor](scala.meta.Ctor.ClassifierClass[scala.meta.Stat]).`unary_!`)))
found that scala.meta.classifiers.`package`.XtensionClassifiable[scala.meta.Template](templ)(scala.meta.Tree.classifiable[scala.meta.Template]).is[Template.Quasi](Template.this.Quasi.ClassifierClass[scala.meta.Template]) is false
and also templ.stats.forall(((x: scala.meta.Stat) => scala.meta.classifiers.`package`.XtensionClassifiable[scala.meta.Stat](x)(scala.meta.Tree.classifiable[scala.meta.Stat]).is[Ctor](scala.meta.Ctor.ClassifierClass[scala.meta.Stat]).`unary_!`)) is false
where Template = scala.meta.Template$@7759c8f1
where templ = {
// one-arg auxiliary constructor
def this(crustSize: Int) = {
this(crustSize, DefaultCrustType)
}
// one-arg auxiliary constructor
def this(crustType: String) = {
this(DefaultCrustSize, crustType)
}
// zero-arg auxiliary constructor
def this() = {
this(DefaultCrustSize, DefaultCrustType)
}
override def toString = s"A $crustSize inch pizza with a $crustType crust"
}
at org.scalameta.invariants.InvariantFailedException$.raise(Exceptions.scala:19)
at scala.meta.Defn$Trait$.internal7(Trees.scala:432)
at scala.meta.Defn$Trait$.apply(Trees.scala:425)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$traitDef(ScalametaParser.scala:4592)
at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:888)
at scala.meta.internal.parsers.ScalametaParser.traitDef(ScalametaParser.scala:4570)
at scala.meta.internal.parsers.ScalametaParser.tmplDef(ScalametaParser.scala:4548)
at scala.meta.internal.parsers.ScalametaParser.defOrDclOrSecondaryCtor(ScalametaParser.scala:4201)
at scala.meta.internal.parsers.ScalametaParser.nonLocalDefOrDcl(ScalametaParser.scala:4172)
at scala.meta.internal.parsers.ScalametaParser$$anonfun$templateStat.applyOrElse(ScalametaParser.scala:5120)
at scala.meta.internal.parsers.ScalametaParser$$anonfun$templateStat.applyOrElse(ScalametaParser.scala:5114)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:35)
at scala.meta.internal.parsers.ScalametaParser.statSeq(ScalametaParser.scala:5057)
at scala.meta.internal.parsers.ScalametaParser.templateStats(ScalametaParser.scala:5130)
at scala.meta.internal.parsers.ScalametaParser.templateStatSeq(ScalametaParser.scala:5110)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$templateBody(ScalametaParser.scala:4945)
at scala.meta.internal.parsers.ScalametaParser.inBraces(ScalametaParser.scala:800)
at scala.meta.internal.parsers.ScalametaParser.templateBody(ScalametaParser.scala:4945)
at scala.meta.internal.parsers.ScalametaParser.templateBodyOpt(ScalametaParser.scala:4953)
at scala.meta.internal.parsers.ScalametaParser.template(ScalametaParser.scala:4887)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$template(ScalametaParser.scala:4906)
at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:888)
at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:922)
at scala.meta.internal.parsers.ScalametaParser.template(ScalametaParser.scala:4891)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$templateOpt(ScalametaParser.scala:4931)
at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:888)
at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:922)
at scala.meta.internal.parsers.ScalametaParser.templateOpt(ScalametaParser.scala:4923)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$objectDef(ScalametaParser.scala:4682)
at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:888)
at scala.meta.internal.parsers.ScalametaParser.objectDef(ScalametaParser.scala:4674)
at scala.meta.internal.parsers.ScalametaParser.tmplDef(ScalametaParser.scala:4558)
at scala.meta.internal.parsers.ScalametaParser.topLevelTmplDef(ScalametaParser.scala:4540)
at scala.meta.internal.parsers.ScalametaParser$$anonfun$topStat.applyOrElse(ScalametaParser.scala:5079)
at scala.meta.internal.parsers.ScalametaParser$$anonfun$topStat.applyOrElse(ScalametaParser.scala:5067)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:35)
at scala.meta.internal.parsers.ScalametaParser.statSeq(ScalametaParser.scala:5057)
at scala.meta.internal.parsers.ScalametaParser.topStatSeq(ScalametaParser.scala:5066)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$batchSource(ScalametaParser.scala:5297)
at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:888)
at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:922)
at scala.meta.internal.parsers.ScalametaParser.batchSource(ScalametaParser.scala:5256)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$source(ScalametaParser.scala:5239)
at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:888)
at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:922)
at scala.meta.internal.parsers.ScalametaParser.source(ScalametaParser.scala:5238)
at scala.meta.internal.parsers.ScalametaParser.entrypointSource(ScalametaParser.scala:5244)
at scala.meta.internal.parsers.ScalametaParser.$anonfun$parseSource(ScalametaParser.scala:143)
at scala.meta.internal.parsers.ScalametaParser.parseRule(ScalametaParser.scala:53)
at scala.meta.internal.parsers.ScalametaParser.parseSource(ScalametaParser.scala:143)
at scala.meta.parsers.Parse$.$anonfun$parseSource(Parse.scala:29)
at scala.meta.internal.parsers.ScalametaParser$$anon4.apply(ScalametaParser.scala:5308)
at scala.meta.parsers.Api$XtensionParseDialectInput.parse(Api.scala:25)
at scala.meta.parsers.Api$XtensionParseInputLike.parse(Api.scala:14)
at com.olegych.scastie.instrumentation.Instrument$.apply(Instrument.scala:199)
at com.olegych.scastie.instrumentation.InstrumentedInputs$.apply(InstrumentedInputs.scala:23)
at com.olegych.scastie.sbt.SbtProcess$$anonfun.applyOrElse(SbtProcess.scala:191)
at com.olegych.scastie.sbt.SbtProcess$$anonfun.applyOrElse(SbtProcess.scala:177)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:35)
at akka.actor.FSM.processEvent(FSM.scala:707)
at akka.actor.FSM.processEvent$(FSM.scala:704)
at com.olegych.scastie.sbt.SbtProcess.processEvent(SbtProcess.scala:64)
at akka.actor.FSM.akka$actor$FSM$$processMsg(FSM.scala:701)
at akka.actor.FSM$$anonfun$receive.applyOrElse(FSM.scala:695)
at akka.actor.Actor.aroundReceive(Actor.scala:539)
at akka.actor.Actor.aroundReceive$(Actor.scala:537)
at com.olegych.scastie.sbt.SbtProcess.aroundReceive(SbtProcess.scala:64)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:614)
at akka.actor.ActorCell.invoke(ActorCell.scala:583)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:268)
at akka.dispatch.Mailbox.run(Mailbox.scala:229)
at akka.dispatch.Mailbox.exec(Mailbox.scala:241)
at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
为什么?为什么它在第 1 行之后,看起来非常好并且在我删除其余部分时被接受? “不变失败”是否意味着它是编译器中的错误? (在这种情况下,许多其他编译器会在消息中添加鼓励报告的内容。)
主要问题:
- 特征中是否允许次要(或辅助 - IIUC 这两个术语我看到的显然可以互换表示相同)构造函数?
- 如果有,怎么称呼他们?
- 它们有什么用处(或者将会是,或者在实际拥有它们的另一种语言中)?
The documentation on trait
parameters只提到trait
参数,没有提到trait
构造函数:
Scala 3 allows traits to have parameters, just like classes have parameters.
它还链接到原始 SIP 文档以供参考:
For more information, see Scala SIP 25.
在 SIP-25 – trait
参数 中,它说 [粗体 强调我的]:
In the
ClassDef
of traits, we still do not allow secondary constructors.
然而,这种限制并没有体现在 Syntax Summary 中,它实际上并没有在句法上区分 class
es 和 trait
s。因此,限制纯粹是文档之一,而不是语法规范。
所以,回答你的问题:
Why?
因为您的代码在语法上有效但在语义上无效,并且 ScalaMeta 似乎不期望这种特定类型的语义无效。
And why is it after line 1, which seems perfectly fine and gets accepted when I remove the rest? Does "invariant failed" mean that it's a bug in the compiler? (Many other compilers in such cases add to the message an encouragement to report it.)
这显然不是编译器中的错误,因为异常不是在编译器中抛出,而是在 ScalaMeta 中抛出。
Main questions:
- Are secondary (or auxiliary – IIUC the two terms I've seen used apparently interchangeably mean the same) constructors allowed in traits?
没有。 SIP-25 显然不允许它们。