我了解到scala generic type hierarchy with different attribute name带有提取器的动态多态性可以解决部分问题。但是,我还了解到,猫,小猫和无形状的猫可能是通往清洁解决方案的道路。不幸的是,我还不熟悉任何一个。尝试从之前的示例构建时,我意识到提取器是不够的。
如何创建注射器?也许甚至没有形状?并动态实例化拟合对象。
Beow是使用提取器的更完整示例,并描述了我的编译错误:
import org.apache.spark.sql.{Dataset, SparkSession}
sealed trait Db {
def db: String
def table: String
}
case class DataSource(override val db: String,
override val table: String)
extends Db
trait Feed extends BaseConfiguration
trait FooFeedConfiguration extends Feed {
def fooFeed: DataSource
}
trait FeedDataSourceExtractor[F <: Feed] {
def extract(feedDs: F): DataSource
}
implicit val cellFeedEx = new FeedDataSourceExtractor[FooFeedConfiguration] {
override def extract(feedDS: FooFeedConfiguration) = feedDS.fooFeed
}
trait BaseConfiguration {
def applicationName: String
}
trait SparkDatasetProvider[T <: Product, C <: BaseConfiguration] {
def provide(spark: SparkSession, c: C): Dataset[T]
}
def myFunction[T <: Product, F <: Feed, feedProvider <: SparkDatasetProvider[T, F]](spark: SparkSession, c: F)(implicit feedEx: FeedDataSourceExtractor[F]): Dataset[T] = {
val dataSourceWithInterval = feedEx.extract(c)
//FooFeedProvider.provideAndFilter(
feedProvider.provide( // TODO why does this not compile.
spark,
//new FooFeedConfiguration {
new F {
override val applicationName = c.applicationName
override val feed // TODO need some kind of injector
DataSource(dataSourceWithInterval.db, // real code performs some fancy logic here (on other attribute values)
dataSourceWithInterval.table)
}
)
}
final case class FooFeed(foo: Int, bar: String)
object FeedProvider extends SparkDatasetProvider[FooFeed, FooFeedConfiguration] {
override def provide(spark: SparkSession, c: FooFeedConfiguration) = {
import spark.implicits._
spark.sql(s"select * from ${c.fooFeed.db}.${c.fooFeed.table}").as[FooFeed]
}
}
myFunction[FooFeed, FooFeedConfiguration, FeedProvider[FooFeed, FooFeedConfiguration]]()
// cant call FeedProvider
// all these type parameters (duplicated) seem to be not elegant. Is there a better way?