从抽象类继承的Case类

18

我正在学习Scala,但在设计我的案例类时遇到了一些问题。我需要两个具有相同属性的案例类。因此,我认为从定义这些属性的抽象基类继承是一个好主意。然而,这段代码无法编译。

abstract class Resource(val uri : String)

case class File(uri : String) extends Resource(uri)
case class Folder(uri : String) extends Resource(uri)

之所以在case类构造函数中使用uri会覆盖基类的uri属性。

那正确的设计方式是什么?

我想能够做到这样的效果

val arr = Array[Resource](File("test"), Folder("test2"))

arr.foreach { r : Resource => r match {
  case f : File => println("It's a file")
  case f : Folder => println("It's a folder")
} }

"等价的" Java 代码应该是这样的

abstract class Resource {
   private String uri;

   public Resource(String uri) {
       this.uri = uri
   }

   public String getUri() {
       return uri;
   }
}

// same for Folder
class File extends Resource {
    public File(String uri) {
        super(uri);
    }
}
2个回答

28

正确的语法应该是:

abstract class Resource {
   val uri: String
}

case class File(uri : String) extends Resource
case class Folder(uri : String) extends Resource


Stream[Resource](File("test"), Folder("test2")) foreach { 
  r : Resource => r match {
   case f : File => println("It's a file")
   case f : Folder => println("It's a folder")
} }

编辑

不使用case类:

abstract class Resource(val uri : String)

class File(uri : String) extends Resource(uri) {
   override def toString = "..."
}
object File {
   def apply(uri: String) = new File(uri)
}

class Folder(uri : String) extends Resource(uri) {
   override def toString = "..."
}
object Folder {
   def apply(uri: String) = new Folder(uri)
}

1
然而,这会在FileFolder中重复uri属性和getter。有没有可能获得干净的代码,看起来像我问题中的Java示例? - Sven Jacobs
那么为什么要使用 case classes?Case classes 添加 getter 和 setter。编写普通类及其伴生对象。 - onof
因为这将会是太多的重复代码?;-) 你能给出一个例子吗? - Sven Jacobs
谢谢!我不需要一个 unapply(),因为 case f : File => 匹配对象的类? - Sven Jacobs
是的,如果你想写类似于:r match { case File(b) => ... } 这样的代码,你需要使用 unapply。 - onof

5
让这两个case class 实现一个共同的trait,该trait定义了它们的接口,这样就可以正常工作了。
顺便提一下,在case语句中的类型声明前需要加上标识符。
trait Resource {
    val uri: String
}

case class File(uri : String) extends Resource
case class Folder(uri : String) extends Resource

val arr = Array[Resource](File("test"), Folder("test2"))

arr.foreach { r : Resource => r match {
  case s: File => println("It's a file")
  case s: Folder => println("It's a folder")
}}

1
这个代码是可以工作的,但是FileFolder类中都有uri属性和getter方法(重复了)。我希望像上面的Java示例代码一样能够写出一些简洁明了的代码(我已经更新了我的问题)。 - Sven Jacobs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接