Делать это с неявным преобразованием опасно по той же причине, по которой (A) => B
не должен наследоваться от PartialFunction[A, B]
.Таким образом, контракт PartialFunction гарантирует, что вы можете безопасно * позвонить apply
, куда бы isDefinedAt
не вернул true
.Контракт Function1 не предоставляет такой гарантии.
Ваше неявное преобразование приведет к PartialFunction, которая нарушает его контракт, если вы примените его к функции, которая не определена повсеместно.Вместо этого используйте сутенера, чтобы сделать преобразование явным:
implicit def funcAsPartial[A, B](f: A => B) = new {
/** only use if `f` is defined everywhere */
def asPartial(): PartialFunction[A, B] = {
case a => f(a)
}
def asPartial(isDefinedAt: A => Boolean): PartialFunction[A, B] = {
case a if isDefinedAt(a) => f(a)
}
}
// now you can write
val f = (i: Int) => i * i
val p = f.asPartial // defined on all integers
val p2 = f.asPartial(_ > 0) // defined only on positive integers
* Как обсуждалось в комментариях, может быть не совсем понятно, что означает здесь «безопасность».Я думаю об этом, что PartialFunction явно объявляет свою область в следующем точном смысле: если isDefinedAt
возвращает значение true для значения x
, тогда apply(x)
может быть оценено способом, который согласуется с намерениемавтор функции.То, что не означает, что apply(x)
не будет вызывать исключение, а лишь означает, что исключение было частью конструкции функции (и должно быть задокументировано).