实际上可以弃用Scala案例类字段吗?

时间:2018-03-20 13:20:39

标签: scala case-class

鉴于

case class Fruit(name: String, colour: String)

我想弃用案例类字段colour

我试图通过使用Scala @deprecated

来实现前者
case class Fruit(name: String, @deprecated("message", "since") colour: String)

和Java @Deprecated注释

case class Fruit(
  name: String, 
  /* @Deprecated with some message here */
  @(Deprecated @field) 
  colour: String
)

不幸的是,我无法在任何情况下使colour弃用,而且我无法找到任何资源。

实际上,我可以使用其他方法实现相同的任务,例如通过将我的case类放宽到普通类并为getter提供colour并使后者弃用,但我想知道是否实际上不可能弃用case类字段并且 - 最终 - 原因。

谢谢。

更新

正如Mike正确指出的那样,colour是案例类的必填字段,因此将此属性设置为deprecated的意义是有争议的。我想弃用colour,因为我现在提供来自其他构造的colour信息,我想让用户知道colour不是正确的实例通过哪里获取该信息,我将在下一版本中将其从Fruit中删除。

到目前为止,我只是警告用户不要从Fruit属性中获取colour信息,暂时,如果他们可以创建带有颜色信息的水果实例,我真的不在乎

更新2

正如Alexey所说,我在编译时确实有不赞成的警告。但是为什么我不能在IDE代码中看到弃用以及我弃用某个方法呢?我期待类似下面的内容

val fruit = Fruit("peer", "green")
val colour = fruit.colour

我正在使用IntelliJ。

3 个答案:

答案 0 :(得分:5)

这是一个奇怪的用例。如果必填字段已弃用,那么该类本身也必须已弃用,当然?也就是说,假设您尝试做的事情是可能的,那么在没有获得弃用警告的情况下,无法在所有中使用类。 (这可能解释了为什么它不可能。)

那就是说,正如你所指出的那样,有很多方法可以实现你想要做的事情。这是其中之一:

case class Fruit(name: String) {

  @deprecated("message", "since")
  val colour: String = "some default value"
}

object Fruit {

  // Deprecated factory method.
  @deprecated("message", "since")
  def apply(name: String,  colour: String): Fruit = Fruit(name)
}

显然,这假设不再需要colour作为Fruit的属性。 (如果 是必需的,则不应该弃用。)它的工作原理是弃用创建Fruit工厂方法一个colour值。

如果这不起作用,您能否解释为什么该字段需要弃用

答案 1 :(得分:2)

您的第一个版本似乎工作正常:如果您粘贴

case class Fruit(name: String, @deprecated("message", "since") colour: String)

println(Fruit("", "").colour)

https://scastie.scala-lang.org/,您会看到弃用警告。当然,您需要直接或通过提取器访问该字段:

Fruit("", "") match { case Fruit(x, y) => y }

也会发出警告。

IDEA没有显示colour被弃用,我认为只是一个错误。一般来说,在Scala代码内联中显示错误和警告是非常不可靠的,您应该始终通过实际构建项目进行检查。

答案 2 :(得分:0)

这很棘手,它还取决于您想要的兼容性级别。

您可以删除该字段(从而将其从主构造函数中删除),但也可以使用旧签名创建不推荐使用的构造函数。另外,您需要在配对对象上使用类似的apply方法。问题是,它会破坏案例类的模式匹配(除非你覆盖unapply)。也许你觉得它合理,也许不是。而且,如果您不想打破读者,您还必须实现已弃用的getter存根。 (但值得回答的是什么价值。)

更保守的方法:弃用主构造函数,创建没有值的辅助(不推荐)构造函数。此外,弃用该字段。这似乎工作正常,它不会破坏unapply方法。它似乎会根据您的需要提出已弃用的警告,但定义也会引发弃用警告。请参阅以下代码段:

case class Foo @deprecated() (x: String, @deprecated y: Int){
  def this(x: String) = this(x, 0)
}

object Foo {
  def apply(x: String) = new Foo(x)
}

println((new Foo("x")).x)
println((new Foo("x", 66)).x)
println((Foo("x")).x)
println((Foo("x", 66)).x)

println((new Foo("x")).y)
println((new Foo("x", 66)).y)
println((Foo("x")).y)
println((Foo("x", 66)).y)

不幸的是,有no @SuppressWarning

当然,根据需要调整@deprecated的参数。