3

假设我正在编写一个 GUI

在此处输入图像描述

class Kitteh (val age: Int) {
  require (age < 5)
  def saveMeow(file: File) = { /* implementation */ }
  def savePurr(file: File) = { /* implementation */ }
}

该框架有一个当前 Kitteh 的字段,这是Option因为它可能尚未定义,或者用户可能试图创建一个无效的:

var currentKitteh: Option[Kitteh] = None

现在我想Kitteh在用户点击创建时安全地创建一个

val a = ... // parse age from text box
currentKitteh = try { Some(new Kitteh(a)) } catch { case _ => None }

我的 GUI 有两个按钮可以做类似的事情。在psedocode中,它们都应该

if (currentKitteh.isDefined) {
  if (file on the disk already exists) {
    bring up a dialog box asking for confirmation
    if (user confirms)
       << execute method on currentKitteh >>
  }
}
else bring up warning dialog

不要担心细节:关键是因为存在代码重复,我想创建一个可以从两个按钮调用的通用方法。唯一的区别是需要执行的 Kitteh 上的方法。

现在如果currentKitteh不是 a Option,通用方法可以有一个签名,如

def save(filename: String, f:(File => Unit)) {

例如,我可以打电话

save("meow.txt", currentKitteh.saveMeow _)

但由于它实际上是一个选项,我该如何实现呢?

我可以检查是否定义了 currentKitteh,并在为每个按钮.get调用save方法之前做一个,但是还有另一种方法,把这个检查留在save方法中吗?换句话说,给定一个Option[A],是否可以从(可能不存在的)A对象上的方法中指定部分函数?

(希望这个问题有意义,尽管有复杂的例子)

编辑:奖金问题:如果Option[Kitteh]我使用了,而不是,怎么Either[Throwable, Kitteh]办?

更新:添加到伪代码的附加行以显示警告对话框:理想情况下,save应始终调用该方法,以便在没有有效的 Kitteh 可保存时警告用户。

4

3 回答 3

4

这对我来说似乎是最好的选择:

currentKitteh foreach { c => save("meow.txt", c.saveMeow _) }

如果你反复这样做,你可以抽象它,

def currentSaveMeow(file: String) = currentKitteh foreach { c =>
  save(file, c.saveMeow _)
}
currentSaveMeow("meow.txt")

我想回答你原来的问题,你也可以将逻辑推入函数参数,

save("meow.txt", file => currentKitten.foreach(_.saveMeow(file)))

这个版本的语义略有不同。

更新。如果k: Option[Kitteh]换成k: Either[Throwable, Kitteh],那又如何k.right foreach { c => ... }呢?k.right map ...如果要保留错误信息,也可以使用。


针对修改后的问题,这是另一种抽象的可能性,

def save(filename: String, f: (Kitteh, File) => Unit)

现在save有拆包的责任currentKittehsave像这样打电话,

save("meow.txt", (k, f) => k.saveMeow(f))

或者像这样,

save("meow.txt", _ saveMeow _)
于 2011-09-08T22:02:27.727 回答
0

您可以将一个函数映射到它并 getOrElse 您的失败函数:

def save = 
  o map {s => () => "saved a kitteh! " + s} getOrElse {() => "oh noes, no kittehs!"}

那么你只需:

save()
于 2011-09-09T19:51:46.033 回答
0

您可以定义一个类 BadKitteh 并让它产生错误消息。然后,如果需要,只需使用 currentKitty.getOrElse(badKitty) 即可。

于 2011-09-10T09:45:47.667 回答