【问题标题】:Scala inherit parameterized constructorScala继承参数化构造函数
【发布时间】:2011-06-27 18:09:57
【问题描述】:

我有一个带有几个可选参数的抽象基类:

abstract case class Hypothesis(
    requirement: Boolean = false,
    onlyDays:   Seq[Int] = Nil,
    …
) extends Something {…}

我真的需要明确地重复所有参数吗在顶部加上额外的关键字override val

case class SomeHypothesis(
    anotherArg: SomeType,
    override val requirement: Boolean = false,
    override val onlyDays:   Seq[Int] = Nil,
    …
) extends Hypothesis(
    requirement,
    onlyDays,
    …
) {…}

或者有没有类似的语法

case class SomeHypothesis(anotherArg: SomeType, **) extends Hypothesis(**) {…}

我什至不需要anotherArg,只是一种将所有关键字参数传递给超级构造函数的方法。


我真的很喜欢 Scala 关于构造函数的想法,但如果没有那个语法,我会失望的 :(

【问题讨论】:

  • 如果可以的话,我会否决这条评论,因为它是错误的。至少对我来说,情况并非如此。请参阅this answer 上的第一条评论。我想你应该用默认参数试试。 (或者我的编译器做的事情和你的不同,但我对此表示怀疑。)
  • 它与默认参数无关,但你是对的:在这种情况下你确实需要override。由于您使用的是案例类,因此所有构造函数参数都隐含地具有 val 修饰符。由于名称冲突,您必须添加显式 override 修饰符(以及显式 val 修饰符,以使解析器满意)。对于仓促的评论,我深表歉意。

标签: scala inheritance constructor


【解决方案1】:

您可以在继承的类中只使用一个虚拟名称:

case class SomeHypothesis(anotherArg: SomeType, rq: Boolean = false, odays: Seq[Int] = Nil)
extends Hypothesis(rq, odays)

但您必须重复默认值。无需覆盖val

编辑:

请注意,您的抽象类不应是案例类。扩展案例类现在是deprecated。你应该为你的抽象类使用extractor

abstract class SomeHypothesis(val request: Boolean)

object SomeHypothesis {
  def unapply(o: Any): Option[Boolean] = o match {
    case sh: SomeHypothesis => Some(sh.request)
    case _ => None
  }
}

【讨论】:

  • 但是编译器先生不同意:overriding value requirement in class Hypothesis of type Boolean; value requirement needs `override' modifier(当我添加它时,编译器先生告诉我'val' expected but identifier found.
  • 啊,现在我明白你的意思了:使用其他名称可以让我不必重写内容。但这只是一个小小的烦恼,因为我仍然必须为所有子类重新编写所有内容。一点也不干>:(
  • 抱歉,我错过了您使用案例类的要点。但是 - 你不应该有一个抽象的案例类 - 扩展案例类是一个弃用的功能。
  • 什么?为什么?而我应该怎么做呢?
  • 关于案例类继承弃用的讨论:scala-programming-language.1934581.n4.nabble.com/…。您应该使用提取器:scala-lang.org/node/112
【解决方案2】:

在我看来,默认值的策略不属于基类,但应该放在具体类中。我会改为执行以下操作:

trait Hypothesis {
  def requirement: Boolean
  def onlyDays: Seq[Int]
  /* other common attributes as necessary */
}

case class SomeHypothesis(anotherArg: SomeType,
                          requirement: Boolean = false,
                          onlyDays: Seq[Int] = Nil)
  extends Hypothesis

SomeHypothesis 的案例类字段将满足 Hypothesis trait 的要求。

正如其他人所说,您仍然可以使用提取器对公共部分进行模式匹配:

object Hypothesis {
  def unapply(h: Hypothesis): (Boolean, Seq[Int]) = (h.requirement, h.onlyDays)
}

【讨论】:

  • 我的问题仍然是我不应该重复自己。而且我真的想要一个在所有子类中行为相同的共享构造函数接口。所以每次我写name: Type = default,我都会重复三次。 (应为 0)
  • 那么也许它们不应该是不同的子类。相反,有一个由额外数据参数化的假设类。也许像 case class Hypothesis[T](info: T, requirement: Boolean = false, onlyDays: Seq[Int] = Nil) 这样的东西,但也许在 T 上绑定了一个类型以确保一些通用接口。
  • 听起来不错。事实上,我需要一个要求、一个期望和一些过滤器(仅几天,...)。然后我需要在过滤后的数据上应用一个 function,它必须为其中一些函数进行分组(可以提供 grouping 标准)。那么我需要通过 expectation(“在 0 到 0.05 范围内”、“true”、“low”)来评估函数结果。此评估的结果可用于需求。 (所有参数强调
【解决方案3】:

我花了几天时间在桌子上敲我的头,试图理解为什么命名参数没有进入扩展类。

我尝试了 trait,copy() 你命名它 - 我和编译器总是不一致,当事情编译时,值永远不会被传递。

所以要清楚你是否有课

class A(someInt:Int = 0, someString: String ="xyz", someOtherString: String = "zyx")  

而你想扩展它:

class B extends A // does NOT compile 

class B(someInt: Int, someString: String, someOtherString: String) extends A // compiles but does not work as expected 

你会认为对 B 的调用是这样的:

case object X = B(someInt=4, someString="Boo", someOtherString="Who") 

实际上要么不能编译(遗憾的是它可以),要么实际上可以工作(它不能)

相反,您需要按如下方式创建 B(是的,这是对上述答案的重复,但起初谷歌将我带到这里时并不明显......)

class B(someInt: Int, someString: String, someOtherString: String) extends A(someInt, someString, someOtherString) 

现在

case object X = B(someInt=4, someString="Boo", someOtherString="Who") 

编译和工作

我还没有计算出可以在 B 类构造函数中放置默认值的内容/时间和位置的所有组合和排列,但我很确定可以在 B 类的定义中使用“预期”指定默认值“ 结果。

【讨论】:

    【解决方案4】:

    如果 Hypothesis 是一个抽象类,那么我就没有它的构造函数。 ID 将这些参数设置为抽象类的抽象属性。

    但是,在这种情况下,您确实需要 override 修饰符。

    【讨论】:

    • 无论如何我都需要它,请参阅我对其他答案的评论。此外,它们总是相同的并且总是具有相同的默认值,所以我不会从抽象类的构造函数中保存超过两个括号。我想保存所有的重复。
    猜你喜欢
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 1970-01-01
    • 2019-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多