假设我正在编写一个 GUI
class Kitteh (val age: Int) {
require (age < 5)
def saveMeow(file: File) = { /* implementation */ }
def savePurr(file: File) = { /* implementation */ }
}
该框架有一个用于当前 Kitteh 的字段,它是一个选项
,因为它可能尚未定义,或者用户可能已尝试创建一个无效的:
var currentKitteh: Option[Kitteh] = None
现在我想在用户点击创建时安全地创建一个 Kitteh
val a = ... // parse age from text box
currentKitteh = try { Some(new Kitteh(a)) } catch { case _ => None }
我的 GUI 有两个按钮,它们做类似的事情。在伪代码中,它们都应该
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
不是一个 Option
,那么通用方法可以有一个像这样的签名
def save(filename: String, f:(File => Unit)) {
例如,我可以调用它
save("meow.txt", currentKitteh.saveMeow _)
但由于它实际上是一个选项,我该如何实现呢?
我可以只检查是否定义了 currentKitteh,并在为每个按钮调用 save
方法之前执行 .get
,但是还有另一种方法,将此检查留在保存
方法?换句话说,给定一个 Option[A]
,是否可以从(可能不存在的)A
对象的方法中指定部分函数?
(希望这个问题是有道理的,尽管有令人费解的例子)
编辑:奖励问题:如果我使用 Either[Throwable, Kitteh]
而不是 Option[Kitteh]
会怎么样?
update:添加到伪代码中以显示警告对话框的附加行:理想情况下,应始终调用 save
方法,以便在没有有效的情况下警告用户Kitteh 保存。
最佳答案
这对我来说是最好的选择:
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
负责解包currentKitteh
。像这样调用save
,
save("meow.txt", (k, f) => k.saveMeow(f))
或者像这样,
save("meow.txt", _ saveMeow _)
关于scala - 从选项中的类型方法生成部分应用的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7354768/