【问题标题】:scala generic method less boilerplatescala 通用方法少样板
【发布时间】:2018-06-19 21:12:59
【问题描述】:

如何防止 Scala 中的泛型方法出现一些代码重复?我的代码仅在类型参数绑定到特征而不是方法时编译。

如你所见,我目前重复传递给 trait 和 mehtod 的类型参数。

trait MyTrait[T <: Product, C <: OtherTrait] {

  def provide(spark: SparkSession, c: C): Dataset[T]
}

object ConcreteProvider
  extends MyTrait[MyCaseClass, MyCaseClassConfiguration] {
    override def provide(
        spark: SparkSession,
        c: MyCaseClassConfiguration): Dataset[MyCaseClass] = {
        spark.sql(s"SELECT field1, field2 FROM ${c.mydb}.${c.mytable}")
          .as[MyCaseClass]
    }
  }

【问题讨论】:

  • 你还需要绑定MyCaseClassMyCaseClassConfigurationCellFeedSubscriberConfiguration,所以不知道你担心什么重复。您没有显示参数cprovide() 中的使用方式。您应该能够将provide 的主体分解为provideHelper 并在特征中定义provide
  • 我编辑了示例以显示c的用法。
  • 什么意思,我还需要绑定?我认为你在 [T] 中引用我的类型参数应该没问题?
  • 确实如此。重命名
  • 另请注意,您的代码可能容易受到 SQL 注入的攻击。您可能应该使用更高级别的 SQL API。对于 Spark,请参阅:stackoverflow.com/questions/41941472/…

标签: scala generics


【解决方案1】:

一般来说,Scala 不会推断方法的类型参数。但是,在您的情况下,您实际上可以使用(非常简洁的)lambda 语法,因为您的示例中的 MyTrait 是“SAM”(单一抽象方法)类型:

val ConcreteProvider: MyTrait[MyCaseClass, MyCaseClassConfiguration] =
    (spark, c) => spark.sql("SELECT ...").as[MyCaseClass]

现在您的参数类型已经很好地推断出来了。

注意事项:

  • ConcreteProvider 现在是 val 而不是 object。对于许多(大多数?)目的而言,这无关紧要。
  • 这不能在顶层定义,因此您可能必须将其放在package object 中。
  • 如果您将另一个抽象方法添加到 MyTrait,这将失败。

【讨论】:

  • 另一个需要注意的是,2.12 没有 Spark,2.11 没有 IIRC,你也需要 -Xexperimental 标志。
猜你喜欢
  • 1970-01-01
  • 2021-11-03
  • 1970-01-01
  • 2017-05-18
  • 1970-01-01
  • 2020-04-18
  • 1970-01-01
  • 2016-05-19
  • 1970-01-01
相关资源
最近更新 更多