我希望能够以多种不同方式读取某些应用程序的数据(例如,从文件中读取数据,从mongo或postgres数据库中获取数据,在运行中对运算数据应用运算符等)。 )也许我错了,但我认为这样做的好方法就是这样(以下只是一个例子):
trait Options
//Pass the path to a data file to the constructor
class FromFileOptionsWrapper(val file: String) extends Options
//Pass the name of a database to the constructor
class FromDBOptionsWrapper(val db: String) extends Options
// A get-data function
def getFileData(opts: FromFileOptionsWrapper): Iterator[DataPoint] = {
val readFromFile = opts.file
//Logic to get data from readFromFile follows.
//Returns an iterator of datapoints that will be consumed by the app.
}
//Another get-data function
def getDBData(opts: FromDBOptionsWrapper): Iterator[DataPoint] = {
val readFromDB = opts.db
//Logic to get data from readFromDB follows.
//Returns an iterator of datapoints that will be consumed by the app.
}
//An app-runner method
def run(opts: Options, dataFunc: (Options) => Iterator[DataPoint] ) {
val data = dataFunc(opts)
data foreach { dataPoint =>
//do the work...
}
}
/* Usage: */
val opts1 = new FromDBOptionsWrapper("my-db")
run(opts1, getDBData)
val opts2 = new FromFileOptionsWrapper("/home/me/data.txt")
run(opts2, getFileData)
问题是这种方法不起作用,run
方法会出现如下错误:
Type missmatch, expected: (Options) => Iterator[DataPoint], actual:
(FromDBOptionsWrapper) => Iterator[DataPoint]
我查看了文档,并且我发现函数类型与其“域”类型相反,因此错误发生是很自然的,因为run
方法期望某种形式{{ 1}}我正在传递像(A) => B
这样的(C) => B
类C
的子类。
我想知道是否有办法克服这个问题。或者,如果您认为该方法完全偏离轨道,并且有一些标准方法可以实现我想要做的事情。
感谢您的帮助
答案 0 :(得分:3)
最简单的解决方案是参数化run
方法:
def run [T <: Options](opts: T, dataFunc: T => Iterator[DataPoint] ) {...}
但一般来说我遵循这个规则:将需要某些类型知识的代码移动到恰好具有该知识的编译单元。
在这种情况下:
trait Options {
def iterator: Iterator[DataPoint]
}
class FromFileOptionsWrapper(val file: String) extends Options {
lazy val iterator: Iterator[DataPoint] = {
val readFromFile = opts.file
//Logic to get data from readFromFile follows.
//Returns an iterator of datapoints that will be consumed by the app.
}
}
def run(opts: Options) {
opts.iterator foreach { dataPoint =>
//do the work...
}
}
答案 1 :(得分:0)
假设,它确实编译了...你怎么可能实现它?
有些功能需要FromFileOptionsWrapper
,有些功能需要FromDBOptionsWrapper
,但您没有其中任何一种,只有Options
。你如何调用传入的函数?
根据yoru Options
确实是什么,有不同的方法可以做你想做的事情。
最简单的,可能是&#34;教授&#34; Options
本身检索数据,而不是将其传递给单独的函数:
trait Options {
def data: Iterator[DataPoint]
}
class FileOptions extends Options {
def data = getFileData(this)
}
class DBOptions extends Options {
def data = getDBData(this)
}
def run(options: Options) = options.data foreach { dataPoint => ... }
但是在这一点上,很明显,你真的不需要Options
开始。为什么不只是def run(it: Iterator[DataPoint]) = it.foreach ..
?
答案 2 :(得分:-1)
您的问题是因为将'getFileData'传递给run方法。不是'opts2'参数。
opts2是Options的子类,可以用作Options参数。
但'FromFileOptionsWrapper'无法转换为''(选项)=&gt;迭代器[DataPoint]'。
FromFileOptionsWrapper是Options的子类。不是父母!