Bir erken iptal kat
Bir kat erken sonlandırmak için en iyi yolu nedir? Basitleştirilmiş bir örnek olarak, ** 5, sayıları toplamak istiyorum ama ben (tek sayı demek) sonlandırmak istiyor olabilirim beklemiyorum bir karşılaşma düşünün. Bu ilk bakışta
def sumEvenNumbers(nums: Iterable[Int]): Option[Int] = {
nums.foldLeft (Some(0): Option[Int]) {
case (Some(s), n) if n % 2 == 0 => Some(s n)
case _ => None
}
}
Ancak, bu çözüm oldukça çirkin (eğer bir bilsem ., gibi.ve bir dönüş -- çok temiz ve net olurdu dosyalarda grup ve en kötüsü, eğer olmayan bir sayı bile karşılaşırsa bile tüm iterable erişir.
Ne erken sona erdirir yazmak için en iyi yol olurdu böyle kat? Sadece git ve bu yinelemeli olarak yazmak, ya da orada daha fazla kabul gören bir yol gerekir?
CEVAP
İlk tercihim genellikle özyineleme kullanmak olacaktır. Sadece biraz daha az kompakt, potansiyel olarak daha hızlı (kesinlikle) yavaş ve erken sonlandırma mantığı daha açık ifade edebilir. Bu durumda garip olan iç içe defs gerekir:
def sumEvenNumbers(nums: Iterable[Int]) = {
def sumEven(it: Iterator[Int], n: Int): Option[Int] = {
if (it.hasNext) {
val x = it.next
if ((x % 2) == 0) sumEven(it, n x) else None
}
else Some(n)
}
sumEven(nums.iterator, 0)
}
Benim ikinci tercihim olurdu return
gibi duruyor her şey sağlam ve sadece ihtiyacımız sarın kat def
sana bir şey dönmek,--bu durum, zaten bir yöntem, böylece:
def sumEvenNumbers(nums: Iterable[Int]): Option[Int] = {
Some(nums.foldLeft(0){ (n,x) =>
if ((n % 2) != 0) return None
n x
})
}
bu durumda özyineleme iterable/yineleyici bir dönüşüm yapmak zorundaydık beri özyineleme ile özellikle şanssız var olsa da) çok daha kompakt. Sinirli denetim akışı her şeyin eşit olduğunda, önlemek için bir şey, ama burada değil. Değerli durumlarda kullanmaktan zarar gelmez.
Eğer ben bunu sık sık ve istediği içinde ortada bir yöntem bir yerde (yani yapamadım sadece dönüş), ben olsam muhtemelen kullanmak özel durum işleme oluşturmak için yerel olmayan bir kontrol akışı. İyi de, hata işleme ne yani, sonuçta, yararlı bir şey sadece zaman değil. Tek numara, izlemesi çok yavaş olan) yığın, ve bu hiç de kolay bir üretme NoStackTrace
alt özellik ControlThrowable
zaten bunu davranışıyla kaçınmaktır. Scala zaten bu dahili olarak kullanır (aslında, bu kapağı içeriden dönüş uygulayan nasıl!). Hadi biz de kendi (bir düzeltme olabilir ama iç içe değil):
import scala.util.control.ControlThrowable
case class Returned[A](value: A) extends ControlThrowable {}
def shortcut[A](a: => A) = try { a } catch { case Returned(v) => v }
def sumEvenNumbers(nums: Iterable[Int]) = shortcut{
Option(nums.foldLeft(0){ (n,x) =>
if ((x % 2) != 0) throw Returned(None)
n x
})
}
Elbette burada return
kullanarak daha iyi, ama shortcut
herhangi bir yerde, sadece koca bir yöntem kaydırmayı koyabilirsiniz unutmayın.
Benim için sırada yeniden hayata erken sonlandırma sinyali diye (ben ya da bir kütüphane bulmak için) kat olacaktır. Bunu yapmanın iki doğal yollardan ama None
fesih ettiğinizi Option
bir değer, değer değil yaymak; veya tamamlanma sinyalleri ikinci göstergesi fonksiyonu kullanmak için. Bu Scalaz kat Kim Stebel gösterdiği tembel zaten ilk durumda kapsar, ikinci (değişken bir uygulama ile) göstereyim:
def foldOrFail[A,B](it: Iterable[A])(zero: B)(fail: A => Boolean)(f: (B,A) => B): Option[B] = {
val ii = it.iterator
var b = zero
while (ii.hasNext) {
val x = ii.next
if (fail(x)) return None
b = f(b,x)
}
Some(b)
}
def sumEvenNumbers(nums: Iterable[Int]) = foldOrFail(nums)(0)(_ % 2 != 0)(_ _)
Sen özyineleme tarafından fesih uygulamak, iade edip, vs. tembellik. size kalmış.)
O ana uygun türevlerini kapsar bence; ayrıca başka bir seçenek vardır, ama bu durumda onları kullanmak istiyorsunuz neden emin değilim. (Iterator
kendisini iyi işe yarasaydı findOrPrevious
, ama değil, ve ekstra çalışma gerektirir bunu elle yapan bir aptal seçeneği kullanın.)
EC2, Amazon mysql iptal başlamak çünkü...
Scala, bir "erken başlatıcı"...
Nasıl bir denetim ve çocuklar için boy...
Nasıl "iptal" bir UİStoryBoa...
Neden geri başka yavaştır erken?...