Tôi có thể sử dụng toán tử phạm vi với câu lệnh if trong Swift không?


196

Có thể sử dụng toán tử phạm vi .....<với câu lệnh if. Có thể một cái gì đó như thế này:

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

Câu trả lời:


425

Bạn có thể sử dụng toán tử "khớp mẫu" ~=:

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

Hoặc câu lệnh chuyển đổi có mẫu biểu thức (sử dụng toán tử khớp mẫu bên trong):

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

Lưu ý rằng ..<biểu thị một phạm vi bỏ qua giá trị trên, vì vậy bạn có thể muốn 200 ... 299hoặc 200 ..< 300.

Thông tin bổ sung: Khi mã trên được biên dịch trong Xcode 6.3 với bật tối ưu hóa, sau đó để kiểm tra

if 200 ... 299 ~= statusCode

thực tế không có lệnh gọi chức năng nào được tạo ra, chỉ có ba lệnh lắp ráp:

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

đây chính xác là mã lắp ráp được tạo ra cho

if statusCode >= 200 && statusCode <= 299

Bạn có thể xác minh rằng với

xcrun -sdk macosx swiftc -O -emit-lắp ráp main.swift

Kể từ Swift 2, điều này có thể được viết là

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

sử dụng khớp mẫu vừa được giới thiệu cho câu lệnh if. Xem thêm Swift 2 - Khớp mẫu trong "nếu" .


1
Thật tuyệt, đây có phải là O (1) không? Ngoài ra, thật tuyệt nếu Swift có một đoạn ngắn cho các câu lệnh chuyển đổi, như Scala chẳng hạn. Nhưng do bạn luôn bị buộc phải xử lý tất cả các khả năng tại thời điểm biên dịch trong Swift, điều đó có thể không thực sự khả thi.
Bầu trời

2
@Sky: Từ mã lắp ráp được tạo, người ta có thể thấy rằng một hàm thư viện func ~= (Range<A>, A) -> Boolđược gọi. Tôi sẽ giả sử rằng hàm này hoạt động với O (1).
Martin R

4
@Downvoter: Một số bình luận giải thích sẽ rất hay, để tôi có thể cải thiện hoặc sửa câu trả lời ...
Martin R

1
@MartinR làm thế nào bạn biết được hàm nào được gọi bởi ngôn ngữ hợp ngữ.Hopper? +1 cho câu trả lời thú vị
codester

3
@codester: Tôi đã biên dịch mã trên dòng lệnh xcrun -sdk macosx swift -emit-assembly main.swiftvà kiểm tra mã lắp ráp. Sau đó, tôi đã sử dụng xcrun swift-demangle ...để khử tên của hàm được gọi. - Thật không may, Xcode chưa thể tạo mã lắp ráp cho các tệp Swift, có lẽ nó sẽ hoạt động trong phiên bản mới hơn.
Martin R

95

Phiên bản này dường như dễ đọc hơn so với khớp mẫu:

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

2
Chính xác những gì tôi đang tìm kiếm
Nazim Kerimbekov

Tôi gặp lỗi này => Không thể tạo Phạm vi với UpperBound <LowerBound
Alfi

9

Đây là một chủ đề cũ, nhưng dường như tôi đang suy nghĩ quá mức về điều này. Dường như với tôi câu trả lời tốt nhất chỉ là

if statusCode >= 200 && statusCode <= 299

Không có

if 200 > statusCode > 299

hình thức mà tôi biết và các giải pháp được đề xuất khác đang thực hiện các cuộc gọi chức năng, khó đọc hơn và có thể thực thi chậm hơn. Phương pháp khớp mẫu là một mẹo hữu ích để biết, nhưng có vẻ như không phù hợp với vấn đề này.

Biên tập:

Cá nhân, tôi thấy toán tử khớp mẫu là gớm ghiếc và mong muốn trình biên dịch sẽ hỗ trợ if x in 1...100cú pháp. Điều đó thật trực quan và dễ đọc hơn nhiềuif 1...100 ~= x


1
Bạn nói đúng rằng phiên bản này tốt hơn để đọc, tôi chỉ cố gắng trả lời câu hỏi rõ ràng "Có thể sử dụng toán tử phạm vi ...?" - Nhưng Xcode 6.3 beta (ở chế độ tối ưu hóa) tạo chính xác ba hướng dẫn lắp ráp cho if 200 ... 299 ~= statusCode, không có chức năng gọi :)
Martin R

13
Trên thực tế if 200 ... 299 ~= statusCodecung cấp cho các cùng mã lắp ráp nhưif statusCode >= 200 && statusCode <= 299
Martin R

6
Trừ khi điều kiện này nằm trong một phần quan trọng được truy cập hàng ngàn lần mỗi giây, lo lắng về chi phí cuộc gọi chức năng là tối ưu hóa sớm. Thậm chí sau đó, tôi lo lắng nhiều hơn về việc gọi hàm đang làm gì hơn là chi phí gọi nó. Mặc dù vậy, công việc tuyệt vời @MartinR đã chứng minh rằng không có chi phí nào.
gà trống

1
@rickster, đủ thật. Tôi vẫn có xu hướng thích các cấu trúc hiệu quả hơn các cấu trúc không hiệu quả như một vấn đề của thói quen (giả sử khả năng đọc là tương tự). Không đến mức tôi lãng phí quá nhiều thời gian của tôi cho nó, nhưng nó vẫn trả tiền để biết chi phí của các phương pháp khác nhau là gì.
Duncan C

1
Đây là trò đùa, nhưng tôi không đồng ý với đề xuất của bạn rằng câu lệnh if của bạn dễ đọc hoặc dễ hiểu hơn câu trả lời được đăng bởi @SerhiiYakovenko. Đơn giản là trên cơ sở DRY - bạn đặt tên "statusCode" hai lần. Trong một phiên gỡ lỗi vào đêm khuya sau khi tôi quyết định rằng một biến khác có tên "statusValue" nên được sử dụng ở đây thay vì "statusCode", tôi chỉ có thể mắc lỗi thay đổi một trong các tên biến chứ không phải là một biến khác .
RenniePet

3

Tôi muốn kiểm tra lỗi 4xx ngoại trừ 401. Đây là mã:

let i = 401

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

2

Tôi cũng thích toán tử Range .contains (), cho đến khi thấy rằng việc triển khai của nó không hiệu quả - https://oleb.net/blog/2015/09/swift-ranges-and-inter đạn /

Chúng ta có thể biểu diễn điều kiện x <0 bằng một phạm vi: (Int.min .. <0) .contains (x) hoàn toàn tương đương. Nó là rất chậm, mặc dù. Việc triển khai mặc định chứa (_ :) đi qua toàn bộ bộ sưu tập và thực hiện một vòng lặp chín triệu triệu lần trong trường hợp xấu nhất không phải là rẻ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.