การพิมพ์ตัวแปรเสริม


118

ฉันกำลังลองใช้โค้ดเหล่านี้

class Student {
    var name: String
    var age: Int?

    init(name: String) {
        self.name = name
    }

    func description() -> String {
        return age != nil ? "\(name) is \(age) years old." : "\(name) hides his age."
    }
}

var me = Student(name: "Daniel")
println(me.description())
me.age = 18
println(me.description())

โค้ดด้านบนสร้างดังต่อไปนี้

Daniel hides his age.
Daniel is Optional(18) years old.

คำถามของฉันคือเหตุใดจึงมีตัวเลือก (18) ที่นั่นฉันจะลบตัวเลือกและเพียงแค่พิมพ์ได้อย่างไร

Daniel is 18 years old.

คำตอบ:


190

คุณต้องเข้าใจว่าตัวเลือกคืออะไรจริงๆ ผู้เริ่มต้นใช้ Swift หลายคนคิดvar age: Int?ว่าอายุคือ Int ซึ่งอาจมีค่าหรือไม่มีก็ได้ แต่หมายความว่าอายุเป็นทางเลือกซึ่งอาจมีหรือไม่มี Int ก็ได้

ภายในdescription()ฟังก์ชันของคุณคุณไม่ได้พิมพ์ Int แต่ให้พิมพ์ตัวเลือกแทน หากคุณต้องการพิมพ์ Int คุณต้องแกะตัวเลือก คุณสามารถใช้ "การผูกแบบเลือกได้" เพื่อแกะตัวเลือกเสริม:

if let a = age {
 // a is an Int
}

หากคุณแน่ใจว่าตัวเลือกนั้นถือวัตถุคุณสามารถใช้ "บังคับแกะ":

let a = age!

หรือในตัวอย่างของคุณเนื่องจากคุณมีการทดสอบศูนย์ในฟังก์ชันคำอธิบายแล้วคุณสามารถเปลี่ยนเป็น:

func description() -> String {
    return age != nil ? "\(name) is \(age!) years old." : "\(name) hides his age."
}

ฉันคิดว่าตัวอย่างจะดีกว่าเล็กน้อยถ้าคุณเปลี่ยนมาใช้if let age = age { return ""} else { return "" }
kubi

13
+1 สำหรับ:Many Swift beginners think var age: Int? means that age is an Int which may or may not have a value. But it means that age is an Optional which may or may not hold an Int.
lee

18

ทางเลือกหมายความว่า Swift ไม่แน่ใจว่าค่าตรงกับประเภท: ตัวอย่างเช่น Int? หมายความว่า Swift ไม่แน่ใจว่าตัวเลขนั้นเป็น Int หรือไม่

ในการลบออกมีสามวิธีที่คุณสามารถใช้

1) หากคุณแน่ใจจริงๆว่าเป็นประเภทใดคุณสามารถใช้เครื่องหมายอัศเจรีย์เพื่อบังคับให้แกะออกได้ดังนี้:

// Here is an optional variable:

var age: Int?

// Here is how you would force unwrap it:

var unwrappedAge = age!

หากคุณบังคับให้แกะอุปกรณ์เสริมและเท่ากับศูนย์คุณอาจพบข้อผิดพลาดนี้:

ใส่คำอธิบายภาพที่นี่

สิ่งนี้ไม่จำเป็นต้องปลอดภัยดังนั้นนี่คือวิธีการที่อาจป้องกันการขัดข้องในกรณีที่คุณไม่แน่ใจประเภทและค่า:

วิธีที่ 2 และ 3 ป้องกันปัญหานี้

2) ตัวเลือกที่ไม่ได้ห่อโดยปริยาย

 if let unwrappedAge = age {

 // continue in here

 }

โปรดทราบว่าขณะนี้ประเภทที่ยังไม่ได้ห่อเป็นIntแทนที่จะเป็นInt? .

3) คำสั่งยาม

 guard let unwrappedAge = age else { 
   // continue in here
 }

จากที่นี่คุณสามารถดำเนินการต่อและใช้ตัวแปรที่ไม่ได้ปิดกั้น ตรวจสอบให้แน่ใจว่าได้บังคับให้แกะออกเท่านั้น (ด้วย!) หากคุณแน่ใจในประเภทของตัวแปร

โชคดีกับโครงการของคุณ!


1
ใช้ return age! = nil? "(ชื่อ) คือ (อายุ!) ปี" : "(ชื่อ) ซ่อนอายุของเขา"
leedream

1
ช่วยให้ฉันปวดหัวกับปัญหาที่ฉันมี ขอบคุณไม่พอ
Bruno Recillas

8

สำหรับวัตถุประสงค์ในการทดสอบ / การดีบักฉันมักต้องการส่งออก optionals เป็นสตริงโดยไม่ต้องทดสอบnilค่าเสมอไปดังนั้นฉันจึงสร้างตัวดำเนินการที่กำหนดเอง

ฉันดีขึ้นสิ่งที่ดียิ่งขึ้นหลังจากที่ได้อ่านคำตอบในคำถามอื่น

fileprivate protocol _Optional {
    func unwrappedString() -> String
}

extension Optional: _Optional {
    fileprivate func unwrappedString() -> String {
        switch self {
        case .some(let wrapped as _Optional): return wrapped.unwrappedString()
        case .some(let wrapped): return String(describing: wrapped)
        case .none: return String(describing: self)
        }
    }
}

postfix operator ~? { }
public postfix func ~? <X> (x: X?) -> String {
    return x.unwrappedString
}

เห็นได้ชัดว่าตัวดำเนินการ (และแอตทริบิวต์) สามารถปรับแต่งได้ตามความต้องการของคุณหรือคุณอาจทำให้เป็นฟังก์ชันแทนก็ได้ อย่างไรก็ตามสิ่งนี้ช่วยให้คุณสามารถเขียนโค้ดง่ายๆเช่นนี้:

var d: Double? = 12.34
print(d)     // Optional(12.34)
print(d~?)   // 12.34
d = nil
print(d~?)   // nil

การบูรณาการแนวคิดโปรโตคอลของคนอื่นทำให้สามารถใช้งานได้กับตัวเลือกที่ซ้อนกันซึ่งมักเกิดขึ้นเมื่อใช้การผูกมัดตัวเลือก ตัวอย่างเช่น:

let i: Int??? = 5
print(i)              // Optional(Optional(Optional(5)))
print("i: \(i~?)")    // i: 5

1
ใน Swift 3 คุณยังสามารถใช้ฟังก์ชัน debugPrint ไลบรารีมาตรฐานของ Swift (_: ตัวคั่น: เทอร์มิเนเตอร์ :) อย่างไรก็ตามสิ่งนี้จะพิมพ์สตริงในเครื่องหมายคำพูดคู่
psmythirl

@psmythirl: น่ารู้! อย่างไรก็ตามบางครั้งคุณอาจต้องการเพียงแค่ส่งหรือฝังตัวเลือกเป็นที่Stringอื่น (เช่นบันทึก / ข้อความแสดงข้อผิดพลาด)
Jeremy

print (d as Any)
DawnSong

7

ปรับปรุง

me.age ?? "Unknown age!"เพียงแค่ใช้ ทำงานใน 3.0.2

คำตอบเก่า

โดยไม่ต้องออกแรงแกะ (ไม่มีสัญญาณเครื่องจักร / พังถ้าไม่มี) อีกวิธีที่ดีในการทำเช่นนี้คือ:

(result["ip"] ?? "unavailable").description.

result["ip"] ?? "unavailable" ควรมีผลงานด้วย แต่ก็ไม่ได้ไม่ใช่อย่างน้อยใน 2.2

แน่นอนแทนที่ "ไม่พร้อมใช้งาน" ด้วยสิ่งที่เหมาะกับคุณ: "nil", "not found" เป็นต้น


4

การแกะใช้ตัวเลือกแทนage! ageขณะนี้คุณกำลังพิมพ์ค่าทางเลือกที่อาจเป็นnilได้ Thats Optionalทำไมมันห่อด้วย


4

อย่างรวดเร็วOptionalเป็นสิ่งที่อาจเกิดขึ้นได้nilในบางกรณี หากคุณแน่ใจ 100% ว่า a variableจะมีค่าบางอย่างเสมอและจะไม่ส่งคืนnilส่วนเพิ่ม!พร้อมกับตัวแปรเพื่อบังคับให้แกะออก

ในกรณีอื่น ๆ หากคุณไม่แน่ใจในมูลค่ามากนักให้เพิ่มif letบล็อกหรือguardตรวจสอบให้แน่ใจว่ามีค่านั้นอยู่มิฉะนั้นอาจทำให้เกิดข้อผิดพลาดได้

สำหรับif letบล็อก:

if let abc = any_variable {
 // do anything you want with 'abc' variable no need to force unwrap now.
}

สำหรับguardคำสั่ง:

guard เป็นโครงสร้างที่มีเงื่อนไขเพื่อส่งคืนการควบคุมหากไม่เป็นไปตามเงื่อนไข

ฉันชอบที่จะใช้guardover if letblock ในหลาย ๆ สถานการณ์เพราะมันทำให้เราสามารถส่งคืนค่าfunctionถ้าไม่มีค่าเฉพาะ เช่นเดียวกับเมื่อมีฟังก์ชันที่ตัวแปรเป็นส่วนประกอบเราสามารถตรวจสอบได้ในคำสั่งยามและไม่มีการส่งคืนของตัวแปร เช่น;

guard let abc = any_variable else { return }

ถ้าตัวแปรมีอยู่เราสามารถใช้ 'abc' ในฟังก์ชันนอกขอบเขตการป้องกันได้


3

ageเป็นประเภททางเลือก: Optional<Int>ดังนั้นหากคุณเปรียบเทียบกับศูนย์จะส่งกลับเท็จทุกครั้งหากมีค่าหรือไม่มี คุณต้องแกะตัวเลือกเพื่อรับค่า

ในตัวอย่างของคุณคุณไม่รู้ว่ามันมีค่าอะไรอยู่หรือเปล่าคุณจึงใช้สิ่งนี้แทน

if let myAge = age {
    // there is a value and it's currently undraped and is stored in a constant
}
else {
   // no value
}

3

ฉันทำสิ่งนี้เพื่อพิมพ์ค่าของสตริง (คุณสมบัติ) จากตัวควบคุมมุมมองอื่น

ViewController.swift

var testString:NSString = "I am iOS Developer"

SecondViewController.swift

var obj:ViewController? = ViewController(nibName: "ViewController", bundle: nil)
print("The Value of String is \(obj!.testString)")

ผลลัพธ์ :

The Value of String is I am iOS Developer

2
คุณไม่ควรบังคับแกะอุปกรณ์เสริม
E-Riddie


3

เมื่อมีค่าเริ่มต้น:

print("\(name) is \(age ?? 0) years old")

หรือเมื่อชื่อเป็นทางเลือก:

print("\(name ?? "unknown") is \(age) years old")


1

ฉันได้รับตัวเลือก ("สตริง") ในเซลล์มุมมองตารางของฉัน

คำตอบแรกดีมาก และช่วยฉันคิดออก นี่คือสิ่งที่ฉันทำเพื่อช่วยมือใหม่อย่างฉัน

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

let description = workout.listOfStrings.first!
cell.textLabel?.text = description

ตอนนี้ดูเหมือนง่ายมาก แต่ใช้เวลาพอสมควรในการคิดออก


-1

นี่ไม่ใช่คำตอบที่แน่นอนสำหรับคำถามนี้ แต่เป็นสาเหตุหนึ่งของปัญหาประเภทนี้ ในกรณีของฉันฉันไม่สามารถลบตัวเลือกออกจากสตริงที่มี "if let" และ "guard let" ได้

ดังนั้นใช้AnyObjectแทนAnyเพื่อลบตัวเลือกออกจากสตริงอย่างรวดเร็ว

โปรดดูลิงก์สำหรับคำตอบ

https://stackoverflow.com/a/51356716/8334818

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