与函数式编程相关的问题。
“一行代码值千言万语”,所以:
class Entry {
var entryOrderId: Option[Int]
def closeEntry(closeOrder: Order) = {
require(entryOrderId.isDefined)
...
}
}
问题:为了关闭一个条目,必须定义entryOrderId。我不想抛出异常(使用'require'函数)并且我不想返回Try(成功/失败)对象,因为调用者不期望任何返回值。你会如何设计这个功能?
(N.b:我标记了Scala,但语言不是这里的问题......)
答案 0 :(得分:3)
根据您的要求,如果来电者真的不关心结果,那么您可以在foreach
上使用entryOrderId
。因此,只有在定义entryOrderId
时才会调用内部块。
class Entry {
var entryOrderId: Option[Int]
def closeEntry(closeOrder: Order) = entryOrderId foreach { id =>
// do something with the `id` ...
}
}
答案 1 :(得分:2)
如果在没有entryOrderId的条目上调用closeEntry
是一个编程错误,它甚至不应该编译。为了强制执行此操作,我将在Entry
上添加一个类型参数。这将使状态更改变得明确,以及closeEntry对条目状态的约束。
class Order
case class Entry[T <: Option[Int]](entryOrderId: T) {
def closeEntry(closeOrder: Order)(implicit ev: T =:= Some[Int]): Unit = {
entryOrderId.get + 42
}
}
如果您在Entry[Option[Int]]
或Entry[None.type]
上调用closeEntry,编译器会抱怨:
scala> Entry(Some(42)).closeEntry(new Order)
scala> Entry(None).closeEntry(new Order)
<console>:11: error: Cannot prove that None.type =:= Some[Int].
Entry(None).closeEntry(new Order)
^
这个解决方案远非完美:
Int
太多)Entry[Some[Int]]
中提取Entry[Option[Int]]
,所以一旦获得Entry[Some[Int]]
在所有这些变化中,我能找到的最好的是:
import scala.language.higherKinds
class Order
case class Entry[T[_]](entryOrderId: T[Int]) {
def closeEntry(order: Order)(implicit withId: WithId[T]): Unit = {
withId.getId(this) + 42
}
}
implicit object Entry extends HasId[Some] {
def getId(entry: Entry[Some]): Int = entry.entryOrderId.get
}
trait WithId[T[_]] {
def getId(entry: Entry[T]): Int
}
(更好,因为类型现在有点短 - Entry[Some]
而不是Entry[Some[Int]]
)
另一个更简单的解决方案是:
sealed trait Entry
case class EntryWithId(val entryOrderId: Int) extends Entry {
def closeEntry(closeOrder: Order): Unit = {
...
}
}
class NewEntry() extends Entry
唯一的问题是你必须为其他最终字段复制粘贴构造函数。