阅读数据的多种功能

时间:2017-06-28 18:00:01

标签: scala

我希望能够以多种不同方式读取某些应用程序的数据(例如,从文件中读取数据,从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) => BC的子类。

我想知道是否有办法克服这个问题。或者,如果您认为该方法完全偏离轨道,并且有一些标准方法可以实现我想要做的事情。

感谢您的帮助

3 个答案:

答案 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的子类。不是父母!