سؤال

هل من الممكن أن يكتب طريقة orElse المعمم من Option أن يأخذ عدد متغير من الحجج؟ وهذا هو، بدلا من:

lazy val o1 = { println("foo"); None }
lazy val o2 = { println("bar"); Some("bar") }
lazy val o3 = { println("baz"); Some("baz") } 
// ...
o1 orElse o2 orElse o3 // orElse ...

هل يمكن استخدام:

orElse(o1, o2, o3) //, ...
هل كانت مفيدة؟

المحلول

ووفقا ل وسكالا اللغة مواصفات (4.6 الإعلانات وظيفة والتعاريف) لا يمكنك تحديد varargs معلمات بالاسم:

ParamType ::= Type
| ‘=>’ Type
| Type ‘*’

scala> def orElse(x : (=> String)*)
<console>:1: error: no by-name parameter type allowed here
       def orElse(x : (=> String)*)

هل يمكن استبدال وسيطة كسول مع وظيفة ونوع التحويل الضمني:

def orElse[T](x : (()=> Option[T])*) : Option[T] = 
    if(x.isEmpty) None else x.first.apply.orElse(orElse((x drop 1) :_*))
implicit def anyToFun0[T](t : => T) : (() => T) = () => t
orElse(o1, o2, o3)

نصائح أخرى

ولقد وجدت هذه المسألة في وقت متأخر :) قليلا. احتمال واحد هو التفاف => A في فئة المساعد جنبا إلى جنب مع وظيفة المساعد لتبسيط إنشائه:

import scala.language.implicitConversions

class Helper[+A](value: => A) extends Function0[A] {
  override def apply(): A = value;
}
object Helper {
  def unapply[A](h: Helper[A]): Option[A] = Some(h());
}
implicit def toHelper[A](body: => A) = new Helper(body);

لا يطلب من مستخرج، هو فقط يسمح مطابقة السهل على المساعد. ثم نستطيع كتابة

def orElse[A](xs: Helper[Option[A]]*): Option[A] =
  xs.collectFirst[A]({
    case Helper(Some(r)) => r;
  })

lazy val o1 = { println("foo"); None }
lazy val o2 = { println("bar"); Some("bar") }
lazy val o3 = { println("baz"); Some("baz") }

orElse(o1, o2, o3) //, ...

وهذا هو مجرد حل مبسط، وهو أحد أكثر واقعية من شأنه أن يكون

def orElse[A](x: Option[A], xs: Helper[Option[A]]*): Option[A]

ومع تنفيذ أكثر كفاءة.


وهناك بالفعل فئة مشابهة لHelper في Scalaz، ودعا Name مع Need تنفيذ يضمن أن الجسم يتم تقييم على الأكثر مرة واحدة. حتى مع Scalaz، فإنه يمكن تنفيذها ك

import scala.language.implicitConversions
import scalaz._
import scalaz.Scalaz._

implicit def toNeed[A](body: => A): Name[A] = Need(body);

def orElse[A](xs: Name[Option[A]]*): Option[A] =
  xs.collectFirst[A]({
    case Name(Some(r)) => r;
  })

lazy val o1 = { println("foo"); None }
lazy val o2 = { println("bar"); Some("bar") }
lazy val o3 = { println("baz"); Some("baz") }

orElse(o1, o2, o3) //, ...
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top