2014-09-23 42 views
1

我似乎無法弄清楚如何鏈接這些函數,任何幫助或建議,將不勝感激。scala中的函數鏈接

// Generic approach to adding flags to a command string 
trait UpdateCommandString { 
    def update[T](option: Option[T], flagName: String)(implicit command: String): String = { 
    if (option.isEmpty) 
     command 
    else if (option.get.isInstanceOf[Boolean]) { 
     if (option.get.asInstanceOf[Boolean]) 
     s"$command $flagName" 
     command 
    } else 
     s"$command $flagName ${option.get.asInstanceOf[String]}"   
    } 
} 

// One example of flags (the program I'm using has literally 50+ flags 
// so there will be a number of case classes that group them into related 
// sets) 
case class Flags(cache: Option[String] = None, 
    errorlog: Option[String] = None, 
    accesslog: Option[String] = None, 
    verbose: Option[Boolean] = Some(false), 
    auth: Option[Boolean] = Some(false)) extends UpdateCommandString { 

    def applyToCommand(implicit command: String): String = { 
    // These seem to apply separately, but I want to chain 
    // them together! 
    update(cache, "-cache") 
    update(errorlog, "-error") 
    update(accesslog, "-access") 
    update(auth, "-do-auth") 
    } 
} 

// An example of what I'm trying to do 
// Given a base command string and a bunch of case classes to apply 
// to that string, I'd like to be able to call applyToCommand and 
// get back the modified command string 
var command = "run_system" 
val f = Flags(Some("asdfasdf"), None, None, Some(true), Some(false)) 
command = f.applyToCommand(command) 

回答

4

我會推薦一個完整的重新設計你當前的方法。

Flags類的每個成員都應該是它自己的案例類,它擴展了常見的Flag類。

因此,您可以定義函數以將不同的標誌組合到一個配置中。這個配置可以在最後一步中用來構建結果字符串。

abstract class Flag(name: String, parameter : Option[String]) 
case class Cache(parameter : Option[String]) extends Flag("-cache", parameter) 
case class ErrorLog(parameter : Option[String]) extends Flag("-errorlog", parameter) 
//... 

type Config = List[Flag] 

def applyToCommand(commandName : String, config : Config) = { 
    def buildString(f:Flag) = 
    s" $f.name${f.parameter.map(" " ++ _).getOrElse("")}" 

    val flagsString = config.map(buildString).mkString("") 
    s"$commandName" ++ flagString 
} 

//Now you can it simply use it as I described above 
val config = List(Cache(Some("asdf")), ErrorLog(None)) 
applyToCommand("run_system", config) 

這使您的代碼更靈活,更容易重構。

最後,這裏有一些建議,你怎麼能修改此設計以更好地滿足您的需求:

  • 如果你需要將你的標誌,你可以把它們中的對象或單獨的文件。或者,如果您想要根據組更改其行爲,則可以增強類層次結構並添加中間層。

  • 您可以將參數從Flag向下移動到案例類別,因此每個標誌都可以定義它是否需要參數,如果有,多少以及是否可選。

  • 你也可以在案例類中實現buildString,這樣每個標誌都可以決定如何格式化自己。

  • 如果你想添加新的標誌,你只需添加一個新的類,就是這樣,不需要添加任何東西到無關的類。

+0

對我的作品,這使得有關標誌更爲複雜的推理 – Hamy 2014-09-23 15:30:51

0

正如@bmaderbacher所解釋的那樣,我認爲你應該在不同的case類中區分不同的標誌。

但是,爲了回答你的問題,您應該修改applyToCommand

def applyToCommand(implicit command: String): String = { 
    var s = update(cache, "-cache")(command) 
    s = update(errorlog, "-error")(s) 
    s = update(accesslog, "-access")(s) 
    s = update(auth, "-do-auth")(s) 
    s 
} 

在這一點上,應該明確的是,你沒有做出正確的選擇爲您Flag類。

我會做這樣的事情:

trait Flag { 
    def toString: String 
} 

case class Command(value: String) { 
    def add(flag: Flag) = Command(value + ' ' + flag.toString) 
    def +(flag: Flag) = add(flag) 
} 

case class Cache(size: Int) extends Flag { 
    def toString = s"--cache $size" 
} 

case object Auth extends Flag { 
    def toString = "--auth" 
} 

現在你可以這樣做:

val command = Command("run") + Cache(500) + Auth