Скала, частичные функции
Есть ли способ создать PartialFunction
кроме как через case
заявление?
Мне любопытно, потому что я хотел бы выразить следующее (scala псевдо вперед!)...
val bi = BigInt(_)
if (bi.isValidInt) bi.intValue
... как частичная функция, и делать
val toInt : PartialFunction[String, Int] = {
case s if BigInt(s).isValidInt => BigInt(s).intValue
}
кажется излишним, так как я создаю BigInt
дважды.
5 ответов
Не уверен, что понимаю вопрос. Но вот моя попытка: почему бы не создать экстрактор?
object ValidBigInt {
def unapply(s: String): Option[Int] = {
val bi = BigInt(s)
if (bi.isValidInt) Some(bi.intValue) else None
}
}
val toInt: PartialFunction[String, Int] = {
case ValidBigInt(i) => i
}
Другой вариант (и это может ответить на вопрос о том, можно ли создать PartialFunction
кроме как с case
дословный):
val toInt = new PartialFunction[String, Int] {
def isDefinedAt(s: String) = BigInt(s).isValidInt
def apply(s: String) = BigInt(s).intValue
}
Однако, поскольку идея частичной функции заключается в том, что она определена только частично, в конце концов, вы все равно будете делать лишние вещи - вам нужно создать большое int для проверки его работоспособности, а затем в приложении функции вы создадите большое int снова...
Я видел проект на Github, который пытался обойти это, несколько кэшируя результаты isDefinedAt
, Если вы перейдете к тестам, вы увидите, что он оказался медленнее, чем стандартная реализация Scala:)
Так что если вы хотите обойти двойную природу isDefinedAt
против apply
, вы должны просто перейти к (полной) функции, которая обеспечивает Option[Int]
в результате.
Я думаю, что вы ищете лифт / лифт. Лифт принимает частичную функцию и превращает ее в функцию, которая возвращает Option. Unlift принимает функцию с одним аргументом, которая возвращает опцию, и возвращает частичную функцию.
import scala.util.control.Exception._
scala> def fn(s: String) = catching(classOf[NumberFormatException]) opt {BigInt(s)}
fn: (s: String)Option[scala.math.BigInt]
scala> val fnPf = Function.unlift(fn)
fnPf: PartialFunction[String,scala.math.BigInt] = <function1>
scala> val fn = fnPf.lift
fn: String => Option[scala.math.BigInt] = <function1>
Тесно связанный, вы также хотите посмотреть на этот ответ для получения информации о cond и condOpt:
scala> import PartialFunction._
import PartialFunction._
scala> cond("abc") { case "def" => true }
res0: Boolean = false
scala> condOpt("abc") { case x if x.length == 3 => x + x }
res1: Option[java.lang.String] = Some(abcabc)
Вы можете выписать PartialFunction
"от руки", если вы хотите:
object pf extends PartialFunction[Int,String] {
def isDefinedAt(in: Int) = in % 2 == 0
def apply(in: Int) = {
if (in % 2 == 0)
"even"
else
throw new MatchError(in + " is odd")
}
Хорошо, я получил это
import java.lang.NumberFormatException
import scala.util.control.Exception._
val toInt: PartialFunction[String, Int] = {
catching(classOf[NumberFormatException]) opt BigInt(_) match {
case Some(bi) if bi.isValidInt => bi.intValue
}
}
Как насчет этого?
val toInt: PartialFunction[String, Int] = (s: String) => BigInt(s) match {
case bi if bi.isValidInt => bi.intValue
}