Range operatörünü Swift'te if ifadesiyle birlikte kullanabilir miyim?


198

Aralık operatörünü ...ve ..<if ifadesiyle kullanmak mümkün mü ? Maye böyle bir şey:

let statusCode = 204
if statusCode in 200 ..< 299 {
  NSLog("Success")
}

Yanıtlar:


428

"Kalıp eşleşmesi" operatörünü kullanabilirsiniz ~=:

if 200 ... 299 ~= statusCode {
    print("success")
}

Veya ifade modelli bir anahtar deyimi (dahili olarak desen eşleme işlecini kullanır):

switch statusCode {
case 200 ... 299:
    print("success")
default:
    print("failure")
}

Not ..<atlar üst değeri, bu nedenle muhtemelen istediğiniz bir dizi gösterir 200 ... 299veya 200 ..< 300.

Ek bilgi: Yukarıdaki kod, optimizasyon açıkken Xcode 6.3'te derlendiğinde, test için

if 200 ... 299 ~= statusCode

aslında hiçbir işlev çağrısı üretilmez, sadece üç montaj talimatı:

addq    $-200, %rdi
cmpq    $99, %rdi
ja  LBB0_1

bu tam olarak aynı derleme kodudur.

if statusCode >= 200 && statusCode <= 299

İle doğrulayabilirsiniz

xcrun -sdk macosx swiftc -O -emit-montaj main.swift

Swift 2'den itibaren, bu şu şekilde yazılabilir

if case 200 ... 299 = statusCode {
    print("success")
}

if ifadeleri için yeni tanıtılan desen eşleştirmeyi kullanarak. Ayrıca bkz. Swift 2 - "if" de desen eşleştirme .


1
Güzel, bu O (1) mi? Ayrıca, Swift'in örneğin Scala gibi anahtar ifadeleri için kısa bir eli olsaydı iyi olurdu. Ancak Swift'te derleme zamanında her zaman tüm olasılıkları ele almak zorunda olduğunuz göz önüne alındığında, bu gerçekten uygun olmayabilir.
Sky

2
@Sky: Oluşturulan montaj kodundan bir kütüphane fonksiyonunun func ~= (Range<A>, A) -> Boolçağrıldığını görebilirsiniz. Ben ediyorum varsayalım bu fonksiyon O (1) ile çalışır.
Martin R

4
@Downvoter: Açıklayan bazı yorumlar iyi olurdu, böylece cevabı geliştirebilir veya düzeltebilirim ...
Martin R

1
@MartinR Montaj dilinin hangi işlevi çağırdığını nasıl anlarsınız? Güzel cevap için +1
Codester

3
@codester: Komut satırındaki kodu derleme ile derledim xcrun -sdk macosx swift -emit-assembly main.swiftve montaj kodunu inceledim. Sonra xcrun swift-demangle ..., çağrılan işlevin adını değiştirirdim. - Ne yazık ki, Xcode Swift dosyaları için henüz montaj kodu oluşturamıyor, belki daha sonraki bir sürümde çalışacak.
Martin R

95

Bu sürüm, desen eşleşmesinden daha okunabilir görünüyor:

if (200 ... 299).contains(statusCode) {
    print("Success")
}

2
Tam olarak aradığım şey
Nazim Kerimbekov

Bu hatayı alıyorum => UpperBound ile aralığı oluşturamıyorum <lowerBound
Alfi

10

Bu eski bir konu, ama bana öyle geliyor ki, bunu fazla düşünüyoruz. Bana öyle geliyor ki en iyi cevap sadece

if statusCode >= 200 && statusCode <= 299

Orada hiçbir

if 200 > statusCode > 299

ve diğer önerilen çözümler okunması daha zor olan ve yürütülmesi daha yavaş olabilecek işlev çağrıları yapıyor. Kalıp eşleştirme yöntemi, bilmek için yararlı bir numaradır, ancak bu soruna zayıf bir uyum gibi görünüyor.

Düzenle:

Şahsen, desen eşleştirme operatörünü iğrenç buluyorum ve derleyicinin if x in 1...100sözdizimini desteklemesini diliyorum . Bu sooooo çok daha sezgisel ve okunması kolayif 1...100 ~= x


1
Bu sürümün okunması daha iyi, sadece "Range operatörünü kullanmak mümkün mü ...?" - Ama Xcode 6.3 beta (optimize edilmiş modda) tam olarak üç montaj talimatı üretiyor if 200 ... 299 ~= statusCode, işlev çağrısı yok :)
Martin R

13
Aslında aynı montaj kodunu if 200 ... 299 ~= statusCodeveririf statusCode >= 200 && statusCode <= 299
Martin R

6
Bu koşul saniyede binlerce kez ziyaret edilen kritik bir bölümde değilse, işlev çağrısı yükü hakkında endişe etmek erken optimizasyondur. O zaman bile, bir işlev çağrısının arama maliyetinden ziyade ne yaptığından endişe ediyorum . Yine de güzel bir iş @MartinR, ne olursa olsun hiçbir maliyeti olmadığını kanıtlamak için.
rickster

1
@rickster, yeterince doğru. Hala alışkanlık olarak verimsiz olanlardan daha verimli yapıları tercih etme eğilimindeyim (okunabilirliğin benzer olduğu varsayılarak). Benim zamanımı çok fazla harcadığım ölçüde değil, ama yine de farklı yaklaşımların maliyetlerinin ne olduğunu bilmek işe yarıyor.
Duncan C

1
Bu nitpicking, ancak if ifadenizin @SerhiiYakovenko tarafından gönderilen cevaptan daha okunabilir veya anlaşılabilir olduğu fikrine katılmıyorum. Sadece DRY temelinde - "statusCode" adını iki kez adlandırırsınız. Burada "statusCode" yerine "statusValue" adlı farklı bir değişkenin kullanılması gerektiğine karar verdikten sonra gece geç saatlerde süren kasvetli hata ayıklama oturumunda, sadece değişken adlarından birini değiştirme hatasını değiştirebilirim, diğerini değil .
RenniePet

3

401 hariç 4xx hatalarını kontrol etmek istedim. İşte kod:

let i = 401

if 400..<500 ~= i, i != 401 {
    print("yes")
} else {
    print("NO")
}

2

Uygulamasının verimsiz olduğunu bulana kadar Range .contains () operatörünü de tercih ettim - https://oleb.net/blog/2015/09/swift-ranges-and-intervals/

X <0 koşulunu bir aralık kullanarak temsil edebiliriz: (Int.min .. <0) .contains (x) tam olarak eşdeğerdir. Yine de oldukça yavaş. İnclude (_ :) öğesinin varsayılan uygulaması tüm koleksiyonda gezer ve en kötü durumda dokuz çeyrek milyon kez bir döngü yürütmek ucuz değildir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.