Scala类型参数和案例类

时间:2013-09-14 21:16:38

标签: scala types

我有这样的功能:

private def fixBrand[T]( item:T ) = item.copy(brand = item.brand.toLowerCase)

这不是编译---抱怨T没有功能副本。 现在我知道我传入的每个项目都是一个案例类。 我怎么能告诉编译器?这些案例类中的每一个都有一个“品牌”字段,但就对象层次结构而言是不相关的。

我以为我读过Scala 2.10有一个功能允许我使用T作为“一个东西”,它具有x,y,...的功能?忘了叫那个功能了!

2 个答案:

答案 0 :(得分:3)

您可以使用结构类型:

def fixBrand[T <: { def copy(t: String): T; def brand: String }](item: T) = item.copy(item.brand.toLowerCase)

答案 1 :(得分:2)

仅从您的功能来看,T具有copy方法并不明确,更不用说此方法也应该brand作为其中一个参数。

我认为你能得到的最接近的是视界的使用,比如

trait WithBrandCopyable[T] {
  def copy(brand: String): T
  def brand: String
}

object Classes {
  case class Class1(brand: String, number: Int)
  case class Class2(factor: Double, brand: String)

  implicit def class1ToWithBrandCopyable(obj: Class1) = new WithBrandCopyable[Class1] {
    def copy(brand: String) = obj.copy(brand = brand)
    def brand = obj.brand
  }

  implicit def class2ToWithBrandCopyable(obj: Class2) = new WithBrandCopyable[Class2] {
    def copy(brand: String) = obj.copy(brand = brand)
    def brand = obj.brand
  }
}

object Main {
  def fixBrand[T <% WithBrandCopyable[T]](obj: T) =
    obj.copy(brand = obj.brand.toLowerCase)

  def main(args: Array[String]) {
    import Classes._  // Import both classes and implicit conversions

    val obj1 = Class1("BrAnD1", 10)
    val obj2 = Class2(0.3, "BRAnd2")

    println(fixBrand(obj1))  // Prints Class1("brand1",10)
    println(fixBrand(obj2))  // Prints Class2(0.3,"brand2")
  }
}

当然,变体是可能的(例如使用完整类型的类),但所有这些都将包含某种形式的含义。

请注意,可以为每个案例类设置WithBrandCopyable一个超级列表,然后使用普通参数的普通上限。我使用隐式转换有两个原因。首先,因为我想保留copy方法。在一些特征中定义copy(brand: String)方法然后在你的case类中继承这个特性是不可能的,因为它会与编译器生成的copy(<case class arguments>)方法冲突,正如Mark在他的评论中提到的那样。其他答案。其次,隐式转换根本不需要您修改案例类 - 编写转换方法就足够了。

但是,这种方法需要一些样板,即接口特征和每个案例类到此特征的隐式转换。我认为可以通过使用宏来减少这个样板,但不是那么多。

这个样板真的有一个原因。 obj.copy(brand = brand)方法调用在源代码中看起来可能相同,但实际上它是对两个完全不同的方法的调用:第一个具有(String, Int) => Class1之类的签名,第二个具有(Double, String) => Class2之类的签名,而不是提到它们属于不具有共同祖先的不同类别。当然,这些调用的字节代码会有所不同。宏在这方面会有所帮助,但据我所知,它们仍然不够强大,至少在当前稳定版本的Scala中完全减少了这个样板。