ฉันสามารถใช้โอเปอเรเตอร์พิสัยกับ if statement ใน Swift ได้หรือไม่?


คำตอบ:


428

คุณสามารถใช้โอเปอเรเตอร์ "pattern-match" ~=:

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

หรือข้อความสั่งสวิตช์ที่มีรูปแบบนิพจน์ (ซึ่งใช้ตัวดำเนินการจับคู่รูปแบบภายใน):

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

โปรดทราบว่า..<หมายถึงช่วงที่ละเว้นค่าบนดังนั้นคุณอาจต้องการ หรือ200 ... 299200 ..< 300

ข้อมูลเพิ่มเติม:เมื่อโค้ดข้างต้นได้รับการรวบรวมใน Xcode 6.3 พร้อมกับเปิดการปรับให้เหมาะสมเพื่อทำการทดสอบ

if 200 ... 299 ~= statusCode

อันที่จริงไม่มีการเรียกใช้ฟังก์ชั่นใด ๆ เลยมีเพียงสามชุดคำสั่ง:

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

นี่เป็นรหัสแอสเซมบลีเดียวกับที่สร้างขึ้นทั้งหมด

if statusCode >= 200 && statusCode <= 299

คุณสามารถยืนยันด้วย

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

ตั้งแต่ Swift 2สามารถเขียนได้ดังนี้

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

ใช้การจับคู่รูปแบบที่เพิ่งแนะนำสำหรับคำสั่ง if ดูเพิ่มเติมSwift 2 - รูปแบบการจับคู่ใน "ถ้า"


1
เจ๋งนี่ O (1) ไหม นอกจากนี้มันจะดีถ้า Swift มีมือสั้น ๆ สำหรับคำสั่งสวิตช์เช่น Scala เป็นต้น แต่เนื่องจากคุณถูกบังคับให้จัดการความเป็นไปได้ทั้งหมดในเวลารวบรวมใน Swift มันอาจไม่เป็นไปได้จริง ๆ
Sky

2
@Sky: จากรหัสประกอบที่สร้างขึ้นจะเห็นว่าฟังก์ชั่นห้องสมุดที่func ~= (Range<A>, A) -> Boolเรียกว่า ฉันคิดว่าฟังก์ชั่นนี้ใช้งานได้กับ O (1)
Martin R

4
@Downvoter: บางความคิดเห็นอธิบายจะดีเพื่อที่ฉันสามารถปรับปรุงหรือแก้ไขคำตอบ ...
มาร์ติน R

1
@MartinR วิธีที่คุณจะได้รู้ว่าฟังก์ชั่นที่เรียกว่าโดยภาษาประกอบสิ่งที่กระโดด +1 สำหรับคำตอบที่ยอดเยี่ยม
อ่าน

3
@codester: ฉันรวบรวมรหัสในบรรทัดคำสั่งด้วยxcrun -sdk macosx swift -emit-assembly main.swiftและตรวจสอบรหัสประกอบ จากนั้นฉันก็xcrun swift-demangle ...จะยกเลิกการย่อชื่อของฟังก์ชันที่เรียกว่า - น่าเสียดายที่ Xcode ยังไม่สามารถสร้างรหัสการประกอบสำหรับไฟล์ Swift ได้บางทีมันอาจจะทำงานในรุ่นที่ใหม่กว่า
Martin R

95

ดูเหมือนว่ารุ่นนี้จะสามารถอ่านได้มากกว่าการจับคู่รูปแบบ:

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

2
สิ่งที่ฉันกำลังค้นหา
Nazim Kerimbekov

ฉันได้รับข้อผิดพลาดนี้ => ไม่สามารถสร้าง Range ด้วย upperBound <lowerBound
Alfi

10

นี่เป็นหัวข้อเก่า แต่ดูเหมือนว่าสำหรับฉันเราคิดมากเกินไป ดูเหมือนว่าคำตอบที่ดีที่สุดสำหรับฉันก็คือ

if statusCode >= 200 && statusCode <= 299

ไม่มี

if 200 > statusCode > 299

แบบฟอร์มที่ฉันทราบและแนวทางแก้ไขปัญหาอื่น ๆ ที่แนะนำกำลังทำการเรียกใช้ฟังก์ชันซึ่งยากต่อการอ่านและอาจช้ากว่าในการเรียกใช้งาน วิธีการจับคู่รูปแบบเป็นเคล็ดลับที่มีประโยชน์ที่จะรู้ แต่ดูเหมือนจะไม่พอดีสำหรับปัญหานี้

แก้ไข:

โดยส่วนตัวแล้วฉันพบว่าโอเปอเรเตอร์การจับคู่รูปแบบน่าเกลียดและหวังว่าคอมไพเลอร์จะรองรับif x in 1...100ไวยากรณ์ นั่นเป็นเรื่องที่อ่านได้ง่ายกว่าและง่ายกว่ามากif 1...100 ~= x


1
คุณคิดถูกว่าเวอร์ชันนี้ดีกว่าที่จะอ่านฉันแค่พยายามตอบคำถามที่ชัดเจนว่า "เป็นไปได้ไหมที่จะใช้ตัวดำเนินการช่วง ... ?" - แต่ Xcode 6.3 เบต้า (ในโหมดปรับให้เหมาะสมที่สุด) จะสร้างคำแนะนำในการประกอบสามชุดif 200 ... 299 ~= statusCodeโดยไม่มีการเรียกใช้ฟังก์ชั่น :)
Martin R

13
if 200 ... 299 ~= statusCodeให้รหัสแอสเซมบลีที่เหมือนกันจริง ๆif statusCode >= 200 && statusCode <= 299
Martin R

6
เว้นแต่เงื่อนไขนี้อยู่ในส่วนสำคัญที่ได้รับการเยี่ยมชมหลายพันครั้งต่อวินาทีความกังวลเกี่ยวกับค่าใช้จ่ายในการเรียกใช้ฟังก์ชั่นคือการเพิ่มประสิทธิภาพก่อนวัยอันควร แล้วถึงแม้ฉันกังวลมากขึ้นเกี่ยวกับสิ่งที่เรียกฟังก์ชันจะทำมากกว่าค่าใช้จ่ายของเรียกมันว่า เป็นงานที่ดี @MartinR ที่พิสูจน์ว่าไม่มีค่าใช้จ่าย
rickster

1
@ เล่นกลจริงพอ ฉันยังคงชอบที่จะสร้างสิ่งที่มีประสิทธิภาพมากกว่าสิ่งที่ไม่มีประสิทธิภาพในเรื่องของนิสัย (สมมติว่าอ่านง่ายคล้ายกัน) ไม่เท่าที่ฉันเสียเวลามากเกินไป แต่ก็ยังจ่ายเงินให้รู้ว่าต้นทุนของวิธีการที่แตกต่างกันคืออะไร
Duncan C

1
นี่คือ nitpicking แต่ฉันไม่เห็นด้วยกับข้อเสนอแนะของคุณว่าคำสั่ง if ของคุณนั้นสามารถอ่านหรือเข้าใจได้ดีกว่าคำตอบที่ @SerhiiYakovenko โพสต์ เพียงใช้ DRY - คุณชื่อ "statusCode" สองครั้ง ในเซสชั่นการตรวจแก้จุดบกพร่องปลายตาพร่ามัวหลังจากที่ฉันตัดสินใจว่าควรใช้ตัวแปรอื่นที่ชื่อว่า "statusValue" ที่นี่แทน "statusCode" ฉันอาจทำผิดพลาดในการเปลี่ยนชื่อตัวแปรหนึ่งชื่อและไม่ใช่ชื่ออื่น .
RenniePet

3

ฉันต้องการตรวจสอบข้อผิดพลาด 4xx ยกเว้น 401 นี่คือรหัส:

let i = 401

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

2

ฉันต้องการตัวดำเนินการ Range .contain () เช่นกันจนกระทั่งพบว่าการใช้งานไม่มีประสิทธิภาพ - https://oleb.net/blog/2015/09/swift-ranges-and-intervals/

เราสามารถแสดงเงื่อนไข x <0 โดยใช้ช่วง: (Int.min .. <0) .contain (x) เทียบเท่ากัน มันช้ากว่าอย่างมาก การเริ่มต้นการใช้งานของ contain (_ :) สำรวจการเก็บรวบรวมทั้งหมดและการดำเนินการวนซ้ำเก้าล้านครั้งในกรณีที่เลวร้ายที่สุดนั้นไม่ถูก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.