Выполнение этого с неявным преобразованием опасно по той же причине, что (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)
не будет генерировать исключение, а просто исключение было частью дизайна функции (и должно быть документировано).
Спасибо; У меня было неправильное представление о том, что Function1 подразумевается как определяемый по всему домену. –
@AaronNovstrup: ваше объяснение контракта PartialFunction является единственным, что имеет смысл, но не отражено ScalaDocs (по крайней мере до 2.9.1). «ScalaDocs PartialFunction» утверждает, что: «Частичная функция типа« PartialFunction [A, B] »- это унарная функция, в которой домен необязательно включает все значения типа' A'. Более того, они никогда не утверждают, что безопасно (в каком смысле) вызывать f где бы они ни были определены, и это довольно легко нарушить, как это делает литеральный 'PartialFunction'' {case 0 => 1/0} '. Откуда у вас такая информация? Должен ли быть отправлен отчет об ошибке? – Blaisorblade
@Blaisorblade Я считаю, что я прочитал это объяснение в списке рассылки, когда я изучал Scala (это было какое-то время), и я не смотрел ни одну документацию, когда писал этот ответ. И, да, легко и даже довольно часто нарушать этот контракт (например, обернуть/перестроить исключение в блоке catch). Реальная точка заключается в том, что PartialFunctions определяют свой домен, в то время как обычные функции не имеют (с некоторой нечеткостью о том, что это на самом деле означает). –