Giá trị tùy chọn trong Swift là gì?


267

Từ tài liệu của Apple :

Bạn có thể sử dụng ifletcùng nhau làm việc với các giá trị có thể bị thiếu. Các giá trị này được biểu diễn dưới dạng tùy chọn. Một giá trị tùy chọn chứa giá trị hoặc chứa nilđể chỉ ra rằng giá trị bị thiếu. Viết một dấu hỏi ( ?) sau loại giá trị để đánh dấu giá trị là tùy chọn.

Tại sao bạn muốn sử dụng một giá trị tùy chọn?



1
Tùy chọn cũng có thể được xem như là một triển khai của Tùy chọn / Có thể là đơn nguyên . Blog này ở đây làm tốt công việc cố gắng giải thích những gì là một khái niệm khó khăn.
StuartLC

tldr: Vượt qua Swift cần bạn rõ ràng về việc khi nào một giá trị có thể bị mất và khi nào nó được đảm bảo tồn tại. từ câu trả lời xuất sắc
jonatan

Câu trả lời:


531

Tùy chọn trong Swift là loại có thể giữ giá trị hoặc không có giá trị. Tùy chọn được viết bằng cách nối thêm ?bất kỳ loại nào:

var name: String? = "Bertie"

Tùy chọn (cùng với Generics) là một trong những khái niệm Swift khó hiểu nhất. Vì cách chúng được viết và sử dụng, thật dễ dàng để hiểu sai về những gì chúng là. So sánh các tùy chọn ở trên để tạo một chuỗi bình thường:

var name: String = "Bertie" // No "?" after String

Từ cú pháp, có vẻ như một Chuỗi tùy chọn rất giống với Chuỗi thông thường. Nó không thể. Chuỗi tùy chọn không phải là Chuỗi có bật cài đặt "tùy chọn". Nó không phải là một chuỗi đặc biệt. Chuỗi và Chuỗi tùy chọn là các loại hoàn toàn khác nhau.

Đây là điều quan trọng nhất cần biết: Một tùy chọn là một loại container. Chuỗi tùy chọn là một thùng chứa có thể chứa Chuỗi. Một Int tùy chọn là một thùng chứa có thể chứa một Int. Hãy nghĩ về một tùy chọn như một loại bưu kiện. Trước khi bạn mở nó (hoặc "mở khóa" bằng ngôn ngữ của các tùy chọn), bạn sẽ không biết liệu nó có chứa thứ gì hay không.

Bạn có thể xem cách các tùy chọn được triển khai trong Thư viện chuẩn Swift bằng cách nhập "Tùy chọn" vào bất kỳ tệp Swift nào và nhấp vào nó. Đây là phần quan trọng của định nghĩa:

enum Optional<Wrapped> {
    case none
    case some(Wrapped)
}

Tùy chọn chỉ enumlà một trong hai trường hợp: .nonehoặc .some. Nếu .someđó là một giá trị liên quan, trong ví dụ trên, sẽ là String"Xin chào". Một tùy chọn sử dụng Generics để đưa ra một loại cho giá trị liên quan. Loại một chuỗi tùy chọn không phải là String, nó Optional, hay chính xác hơnOptional<String> .

Mọi thứ Swift làm với các tùy chọn là phép thuật giúp đọc và viết mã trôi chảy hơn. Thật không may, điều này che khuất cách nó thực sự hoạt động. Tôi sẽ trải qua một số thủ thuật sau.

Lưu ý: Tôi sẽ nói về các biến tùy chọn rất nhiều, nhưng cũng tốt để tạo các hằng tùy chọn. Tôi đánh dấu tất cả các biến bằng loại của chúng để giúp dễ hiểu hơn các loại loại được tạo, nhưng bạn không phải trong mã của riêng mình.


Cách tạo tùy chọn

Để tạo tùy chọn, hãy thêm ?vào sau loại bạn muốn bọc. Bất kỳ loại có thể là tùy chọn, ngay cả các loại tùy chỉnh của riêng bạn. Bạn không thể có một khoảng cách giữa loại và ?.

var name: String? = "Bob" // Create an optional String that contains "Bob"
var peter: Person? = Person() // An optional "Person" (custom type)

// A class with a String and an optional String property
class Car {
var modelName: String // must exist
var internalName: String? // may or may not exist
}

Sử dụng tùy chọn

Bạn có thể so sánh một tùy chọn nilđể xem nó có giá trị không:

var name: String? = "Bob"
name = nil // Set name to nil, the absence of a value
if name != nil {
    print("There is a name")
}
if name == nil { // Could also use an "else"
    print("Name has no value")
}

Điều này hơi khó hiểu. Nó ngụ ý rằng một tùy chọn là một điều này hoặc điều khác. Đó là con số không hoặc là "Bob". Điều này không đúng, tùy chọn không chuyển thành thứ khác. So sánh nó với nil là một mẹo để làm cho mã dễ đọc hơn. Nếu một tùy chọn bằng 0, điều này chỉ có nghĩa là enum hiện được đặt thành .none.


Chỉ có tùy chọn có thể được không

Nếu bạn cố gắng đặt một biến không tùy chọn thành không, bạn sẽ gặp lỗi.

var red: String = "Red"
red = nil // error: nil cannot be assigned to type 'String'

Một cách khác để xem xét các tùy chọn là bổ sung cho các biến Swift thông thường. Chúng là đối tác của một biến được đảm bảo có giá trị. Swift là một ngôn ngữ cẩn thận ghét sự mơ hồ. Hầu hết các biến được định nghĩa là không tùy chọn, nhưng đôi khi điều này là không thể. Ví dụ, hãy tưởng tượng một bộ điều khiển xem tải hình ảnh từ bộ đệm hoặc từ mạng. Nó có thể có hoặc không có hình ảnh đó tại thời điểm bộ điều khiển xem được tạo. Không có cách nào để đảm bảo giá trị cho biến hình ảnh. Trong trường hợp này, bạn sẽ phải làm cho nó tùy chọn. Nó bắt đầu như nilvà khi hình ảnh được lấy ra, tùy chọn nhận được một giá trị.

Sử dụng một tùy chọn cho thấy các ý định lập trình viên. So với Objective-C, nơi mà bất kỳ đối tượng nào cũng có thể là con số không, Swift cần bạn rõ ràng về việc khi nào một giá trị có thể bị thiếu và khi nào nó được đảm bảo tồn tại.


Để sử dụng một tùy chọn, bạn "mở khóa" nó

Một tùy chọn Stringkhông thể được sử dụng thay cho thực tế String. Để sử dụng giá trị được bọc bên trong một tùy chọn, bạn phải mở khóa nó. Cách đơn giản nhất để mở khóa tùy chọn là thêm !tên sau tùy chọn. Điều này được gọi là "buộc mở". Nó trả về giá trị bên trong tùy chọn (như loại ban đầu) nhưng nếu tùy chọn là nil, nó gây ra sự cố thời gian chạy. Trước khi mở khóa, bạn nên chắc chắn có một giá trị.

var name: String? = "Bob"
let unwrappedName: String = name!
print("Unwrapped name: \(unwrappedName)")

name = nil
let nilName: String = name! // Runtime crash. Unexpected nil.

Kiểm tra và sử dụng tùy chọn

Bởi vì bạn phải luôn kiểm tra số 0 trước khi hủy và sử dụng tùy chọn, đây là một mẫu phổ biến:

var mealPreference: String? = "Vegetarian"
if mealPreference != nil {
    let unwrappedMealPreference: String = mealPreference!
    print("Meal: \(unwrappedMealPreference)") // or do something useful
}

Trong mẫu này, bạn kiểm tra xem có một giá trị nào không, sau đó khi bạn chắc chắn nó có giá trị, bạn buộc mở khóa nó thành một hằng số tạm thời để sử dụng. Vì đây là việc thường làm, Swift cung cấp lối tắt bằng cách sử dụng "nếu cho phép". Điều này được gọi là "ràng buộc tùy chọn".

var mealPreference: String? = "Vegetarian"
if let unwrappedMealPreference: String = mealPreference {
    print("Meal: \(unwrappedMealPreference)") 
}

Điều này tạo ra một hằng số tạm thời (hoặc biến nếu bạn thay thế letbằng var) có phạm vi là chỉ trong vòng nếu của niềng răng. Vì phải sử dụng một tên như "unsrappingMealPreference" hoặc "realMealPreference" là một gánh nặng, Swift cho phép bạn sử dụng lại tên biến ban đầu, tạo một tên tạm thời trong phạm vi khung

var mealPreference: String? = "Vegetarian"
if let mealPreference: String = mealPreference {
    print("Meal: \(mealPreference)") // separate from the other mealPreference
}

Đây là một số mã để chứng minh rằng một biến khác nhau được sử dụng:

var mealPreference: String? = "Vegetarian"
if var mealPreference: String = mealPreference {
    print("Meal: \(mealPreference)") // mealPreference is a String, not a String?
    mealPreference = "Beef" // No effect on original
}
// This is the original mealPreference
print("Meal: \(mealPreference)") // Prints "Meal: Optional("Vegetarian")"

Ràng buộc tùy chọn hoạt động bằng cách kiểm tra xem nếu tùy chọn bằng không. Nếu không, nó sẽ hủy tùy chọn thành hằng số được cung cấp và thực thi khối. Trong Xcode 8.3 trở lên (Swift 3.1), cố gắng in một tùy chọn như thế này sẽ gây ra một cảnh báo vô ích. Sử dụng tùy chọn debugDescriptionđể tắt tiếng:

print("\(mealPreference.debugDescription)")

Tùy chọn cho là gì?

Tùy chọn có hai trường hợp sử dụng:

  1. Những điều có thể thất bại (tôi đã mong đợi một cái gì đó nhưng tôi không có gì)
  2. Những thứ không có gì bây giờ nhưng có thể là thứ gì đó sau này (và ngược lại)

Một số ví dụ cụ thể:

  • Một tài sản có thể ở đó hoặc không ở đó, như middleNamehoặc spousetrong một Personlớp
  • Một phương thức có thể trả về một giá trị hoặc không có gì, như tìm kiếm một kết quả khớp trong một mảng
  • Một phương thức có thể trả về kết quả hoặc gặp lỗi và không trả về gì, như cố đọc nội dung của tệp (thường trả về dữ liệu của tệp) nhưng tệp không tồn tại
  • Thuộc tính đại biểu, không phải luôn luôn được đặt và thường được đặt sau khi khởi tạo
  • Đối với weakcác thuộc tính trong các lớp. Điều họ chỉ đến có thể được đặt thành nilbất cứ lúc nào
  • Một nguồn tài nguyên lớn có thể phải được phát hành để lấy lại bộ nhớ
  • Khi bạn cần một cách để biết khi nào một giá trị đã được đặt (dữ liệu chưa được tải> dữ liệu) thay vì sử dụng một dữ liệu riêng được tải Boolean

Các tùy chọn không tồn tại trong Objective-C nhưng có một khái niệm tương đương, trả về con số không. Các phương thức có thể trả về một đối tượng có thể trả về nil thay vào đó. Điều này được hiểu là "sự vắng mặt của một đối tượng hợp lệ" và thường được sử dụng để nói rằng đã xảy ra sự cố. Nó chỉ hoạt động với các đối tượng Objective-C, không hoạt động với các kiểu C nguyên thủy hoặc cơ bản (enums, structs). Mục tiêu-C thường có các loại chuyên biệt để biểu thị sự vắng mặt của các giá trị này ( NSNotFoundthực sự NSIntegerMax, kCLLocationCoordinate2DInvalidđể biểu thị tọa độ không hợp lệ -1hoặc một số giá trị âm cũng được sử dụng). Lập trình viên phải biết về các giá trị đặc biệt này để chúng phải được ghi lại và học hỏi cho từng trường hợp. Nếu một phương thức không thể lấynil làm tham số, thì điều này phải được ghi lại. Trong Mục tiêu-C,nillà một con trỏ giống như tất cả các đối tượng được định nghĩa là con trỏ, nhưng là một nghĩa đen có nghĩa là sự vắng mặt của một loại nhất định.nil trỏ đến một địa chỉ (không) cụ thể. Trong Swift,nil


So sánh với nil

Bạn đã từng có thể sử dụng bất kỳ tùy chọn nào dưới dạng Boolean:

let leatherTrim: CarExtras? = nil
if leatherTrim {
    price = price + 1000
}

Trong các phiên bản gần đây hơn của Swift, bạn phải sử dụng leatherTrim != nil. Tại sao lại thế này? Vấn đề là một Booleancó thể được bọc trong một tùy chọn. Nếu bạn có Booleannhư thế này:

var ambiguous: Boolean? = false

nó có hai loại "sai", một loại không có giá trị và một loại có giá trị nhưng giá trị là false. Swift ghét sự mơ hồ vì vậy bây giờ bạn phải luôn kiểm tra tùy chọn chống lại nil.

Bạn có thể tự hỏi điểm của một tùy chọn Booleanlà gì? Cũng như các tùy chọn khác, .nonetrạng thái có thể chỉ ra rằng giá trị vẫn chưa được biết. Có thể có một cái gì đó ở đầu bên kia của một cuộc gọi mạng cần một chút thời gian để thăm dò ý kiến. Booleans tùy chọn cũng được gọi là " Booleans ba giá trị "


Thủ thuật nhanh

Swift sử dụng một số thủ thuật để cho phép các tùy chọn hoạt động. Hãy xem xét ba dòng mã tùy chọn tìm kiếm thông thường này;

var religiousAffiliation: String? = "Rastafarian"
religiousAffiliation = nil
if religiousAffiliation != nil { ... }

Không có dòng nào trong số này nên biên dịch.

  • Dòng đầu tiên thiết lập một Chuỗi tùy chọn bằng cách sử dụng một chuỗi ký tự, hai loại khác nhau. Ngay cả khi đây là một Stringloại khác nhau
  • Dòng thứ hai đặt một Chuỗi tùy chọn thành 0, hai loại khác nhau
  • Dòng thứ ba so sánh một chuỗi tùy chọn với nil, hai loại khác nhau

Tôi sẽ xem qua một số chi tiết triển khai của các tùy chọn cho phép các dòng này hoạt động.


Tạo một tùy chọn

Sử dụng ?để tạo một tùy chọn là đường cú pháp, được kích hoạt bởi trình biên dịch Swift. Nếu bạn muốn thực hiện theo cách lâu dài, bạn có thể tạo một tùy chọn như thế này:

var name: Optional<String> = Optional("Bob")

Trình Optionalkhởi tạo đầu tiên này gọi , khởi tạo public init(_ some: Wrapped)kiểu liên kết của tùy chọn từ loại được sử dụng trong ngoặc đơn.

Cách thậm chí dài hơn để tạo và thiết lập một tùy chọn:

var serialNumber:String? = Optional.none
serialNumber = Optional.some("1234")
print("\(serialNumber.debugDescription)")

Đặt tùy chọn thành nil

Bạn có thể tạo một tùy chọn không có giá trị ban đầu hoặc tạo một tùy chọn có giá trị ban đầu là nil(cả hai đều có cùng kết quả).

var name: String?
var name: String? = nil

nilGiao thức cho phép bằng nhau được kích hoạt bởi giao thức ExpressibleByNilLiteral(được đặt tên trước đó NilLiteralConvertible). Tùy chọn được tạo bằng trình Optionalkhởi tạo thứ hai , public init(nilLiteral: ()). Các tài liệu nói rằng bạn không nên sử dụng ExpressibleByNilLiteralcho bất cứ điều gì ngoại trừ tùy chọn, vì điều đó sẽ thay đổi ý nghĩa của con số không trong mã của bạn, nhưng bạn có thể làm điều đó:

class Clint: ExpressibleByNilLiteral {
    var name: String?
    required init(nilLiteral: ()) {
        name = "The Man with No Name"
    }
}

let clint: Clint = nil // Would normally give an error
print("\(clint.name)")

Giao thức tương tự cho phép bạn đặt tùy chọn đã được tạo thành nil. Mặc dù điều đó không được khuyến khích, bạn có thể sử dụng trình khởi tạo bằng chữ không trực tiếp:

var name: Optional<String> = Optional(nilLiteral: ())

So sánh một tùy chọn với nil

Tùy chọn xác định hai toán tử "==" và "! =" Đặc biệt mà bạn có thể thấy trong Optionalđịnh nghĩa. Cái đầu tiên ==cho phép bạn kiểm tra xem có tùy chọn nào bằng 0 không. Hai tùy chọn khác nhau được đặt thành .none sẽ luôn bằng nhau nếu các loại liên kết giống nhau. Khi bạn so sánh với con số không, đằng sau hậu trường, Swift tạo ra một tùy chọn cùng loại được liên kết, được đặt thành .none sau đó sử dụng tùy chọn đó để so sánh.

// How Swift actually compares to nil
var tuxedoRequired: String? = nil
let temp: Optional<String> = Optional.none
if tuxedoRequired == temp { // equivalent to if tuxedoRequired == nil
    print("tuxedoRequired is nil")
}

==Toán tử thứ hai cho phép bạn so sánh hai tùy chọn. Cả hai phải cùng loại và loại đó cần tuân thủ Equatable(giao thức cho phép so sánh mọi thứ với toán tử "==" thông thường). Swift (có lẽ) mở ra hai giá trị và so sánh chúng trực tiếp. Nó cũng xử lý trường hợp một hoặc cả hai tùy chọn.none . Lưu ý phân biệt giữa so sánh với nilnghĩa đen.

Hơn nữa, nó cho phép bạn so sánh bất kỳ Equatableloại nào với một gói tùy chọn loại đó:

let numberToFind: Int = 23
let numberFromString: Int? = Int("23") // Optional(23)
if numberToFind == numberFromString {
    print("It's a match!") // Prints "It's a match!"
}

Đằng sau hậu trường, Swift kết thúc việc không tùy chọn là một tùy chọn trước khi so sánh. Nó cũng hoạt động với nghĩa đen ( if 23 == numberFromString {)

Tôi đã nói có hai ==toán tử, nhưng thực sự có một phần ba cho phép bạn đặt nilở phía bên trái của so sánh

if nil == name { ... }

Tùy chọn đặt tên

Không có quy ước Swift để đặt tên các loại tùy chọn khác với các loại không tùy chọn. Mọi người tránh thêm một cái gì đó vào tên để cho thấy rằng đó là một tùy chọn (như "tùy chọnMiddleName" hoặc "ossibleNumberAsString") và để khai báo cho thấy đó là một loại tùy chọn. Điều này trở nên khó khăn khi bạn muốn đặt tên một cái gì đó để giữ giá trị từ một tùy chọn. Tên "middleName" ngụ ý rằng đó là loại Chuỗi, vì vậy khi bạn trích xuất giá trị Chuỗi từ nó, bạn thường có thể kết thúc bằng các tên như "factMiddleName" hoặc "unsrappingMiddleName" hoặc "realMiddleName". Sử dụng ràng buộc tùy chọn và sử dụng lại tên biến để khắc phục điều này.


Định nghĩa chính thức

Từ "Những điều cơ bản" trong ngôn ngữ lập trình Swift :

Swift cũng giới thiệu các loại tùy chọn, xử lý việc không có giá trị. Các tùy chọn cho biết, hoặc có một giá trị, và nó tương đương với x hoặc hoặc không có giá trị nào cả. Các tùy chọn tương tự như sử dụng nil với các con trỏ trong Objective-C, nhưng chúng hoạt động cho bất kỳ loại nào, không chỉ các lớp. Các tùy chọn an toàn và biểu cảm hơn các con trỏ không trong Objective-C và là trung tâm của nhiều tính năng mạnh mẽ nhất của Swift.

Tùy chọn là một ví dụ về thực tế rằng Swift là một ngôn ngữ an toàn. Swift giúp bạn rõ ràng về các loại giá trị mà mã của bạn có thể làm việc với. Nếu một phần mã của bạn mong đợi một Chuỗi, loại an toàn sẽ ngăn bạn chuyển nhầm Int. Điều này cho phép bạn bắt và sửa lỗi càng sớm càng tốt trong quá trình phát triển.


Để kết thúc, đây là một bài thơ từ năm 1899 về các tùy chọn:

Hôm qua trên cầu thang
tôi đã gặp một người đàn ông không ở đó
Anh ấy không ở đó hôm nay
tôi ước, tôi ước anh ấy sẽ đi

Antigonish


Nhiêu tai nguyên hơn:


5
@KaanDedeoglu Thật không may, Steve rất nhiều tùy chọn. Anh ấy đã ở đây và bây giờ thì không.
vua nevan

19
if myStringkhông biên dịch nữa. Bạn cần if myString != nil. Xem tài liệu .
Pang

5
giải thích tốt nhất và rõ ràng nhất cho? và! sử dụng trong Swift tôi tìm thấy trên web. cảm ơn bạn
mindbomb

2
mateo giải thích sâu về các Tùy chọn, đạt đến độ sâu và các ví dụ dễ dàng.
iluvatar_GR

4
Cảm ơn bạn đã giải thích, nó rõ ràng hơn nhiều so với tài liệu của chính Apple.
yeraisisjoe

16

Hãy lấy ví dụ về một lỗi NSError, nếu không có lỗi nào được trả về, bạn muốn làm cho nó trở thành tùy chọn để trả về Nil. Không có điểm nào trong việc gán giá trị cho nó nếu không có lỗi ..

var error: NSError? = nil

Điều này cũng cho phép bạn có một giá trị mặc định. Vì vậy, bạn có thể đặt phương thức thành giá trị mặc định nếu hàm không vượt qua bất cứ thứ gì

func doesntEnterNumber(x: Int? = 5) -> Bool {
    if (x == 5){
        return true
    } else {
        return false
    }
}

Câu "Nếu nó là con số không, kết quả của bất kỳ biểu thức nào với nó cũng là con số không" đơn giản là sai. func isNil<T>(t: T?) -> Bool { return t == nil }sẽ trả về truengay cả khi có một giá trị tùy chọn niltrong biểu thức.
trả lại đúng

Mẫu mã cực kỳ xấu. Bạn không thể nghĩ ra điều gì tốt hơn sao? Tại sao không đơn giản return x == 5? 5 có gì đặc biệt?
Atomosk

Không, 2 năm trước tôi không thể nghĩ ra điều gì tốt hơn. Hôm nay có, nhưng điều này có được điểm? Đúng. Cảm ơn đầu vào @Atomosk, nó thực sự hữu ích.
John Riselvato

12

Bạn không thể có một biến trỏ đến niltrong Swift - không có con trỏ và không có con trỏ null. Nhưng trong một API, bạn thường muốn có thể chỉ ra một loại giá trị cụ thể hoặc thiếu giá trị - ví dụ: cửa sổ của tôi có đại biểu không, và nếu vậy, đó là ai? Tùy chọn là cách an toàn cho bộ nhớ, loại an toàn của Swift để thực hiện việc này.


11

Tôi đã trả lời ngắn gọn, tổng hợp hầu hết những điều trên, để làm sạch sự không chắc chắn trong đầu tôi khi mới bắt đầu:

Đối lập với Objective-C, không có biến nào có thể chứa nil trong Swift, vì vậy loại biến tùy chọn đã được thêm vào (các biến được thêm vào bởi "?"):

    var aString = nil //error

Sự khác biệt lớn là các biến Tùy chọn không lưu trữ trực tiếp các giá trị (như một biến Obj-C bình thường), chúng có hai trạng thái : " có giá trị " hoặc " có nil ":

    var aString: String? = "Hello, World!"
    aString = nil //correct, now it contains the state "has nil"

Đó là, bạn có thể kiểm tra các biến đó trong các tình huống khác nhau:

if let myString = aString? {
     println(myString)
}
else { 
     println("It's nil") // this will print in our case
}

Bằng cách sử dụng "!" hậu tố, bạn cũng có thể truy cập các giá trị được bao bọc trong chúng, chỉ khi chúng tồn tại . (tức là nó không phải là con số không ):

let aString: String? = "Hello, World!"
// var anotherString: String = aString //error
var anotherString: String = aString!

println(anotherString) //it will print "Hello, World!"

Đó là lý do tại sao bạn cần sử dụng "?" và "!" và không sử dụng tất cả chúng theo mặc định. (đây là sự hoang mang lớn nhất của tôi)

Tôi cũng đồng ý với câu trả lời ở trên: Loại tùy chọn không thể được sử dụng làm boolean .


7

Trong các biến C mục tiêu không có giá trị bằng 'nil' (cũng có thể sử dụng các giá trị 'nil' giống như 0 và false), do đó có thể sử dụng các biến trong các câu lệnh có điều kiện (Biến có giá trị giống như 'TRUE 'và những người không có giá trị bằng' FALSE ').

Swift cung cấp loại an toàn bằng cách cung cấp 'giá trị tùy chọn'. tức là nó ngăn ngừa các lỗi hình thành từ việc gán các biến của các loại khác nhau.

Vì vậy, trong Swift, chỉ booleans có thể được cung cấp trên các câu điều kiện.

var hw = "Hello World"

Ở đây, mặc dù 'hw' là một chuỗi, nó không thể được sử dụng trong câu lệnh if như trong mục tiêu C.

//This is an error

if hw

 {..}

Cho rằng nó cần phải được tạo ra như,

var nhw : String? = "Hello World"

//This is correct

if nhw

 {..}

5

Giá trị tùy chọn cho phép bạn hiển thị sự vắng mặt của giá trị. Một chút giống như NULL trong SQL hoặc NSNull trong Objective-C. Tôi đoán đây sẽ là một cải tiến vì bạn có thể sử dụng nó ngay cả đối với các loại "nguyên thủy".

// Reimplement the Swift standard library's optional type
enum OptionalValue<T> {
    case None
    case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)

Trích từ: Apple Inc., Ngôn ngữ lập trình Swift. Sách điện tử. https://itun.es/gb/jEUH0.l


6
nilchỉ là đường cú pháp cho hằng số enum OptionalValue<T>.None( Tloại phù hợp với bối cảnh bạn đang sử dụng nil). ?là một phím tắt cho OptionalValue<T>.Some(T).
rickster

4

Một tùy chọn có nghĩa là Swift không hoàn toàn chắc chắn nếu giá trị tương ứng với loại: ví dụ: Int? có nghĩa là Swift không hoàn toàn chắc chắn liệu số đó có phải là Int hay không.

Để loại bỏ nó, có ba phương pháp bạn có thể sử dụng.

1) Nếu bạn hoàn toàn chắc chắn về loại, bạn có thể sử dụng dấu chấm than để buộc mở khóa, như thế này:

// Here is an optional variable:

var age: Int?

// Here is how you would force unwrap it:

var unwrappedAge = age!

Nếu bạn buộc hủy bỏ tùy chọn và nó bằng 0, bạn có thể gặp phải lỗi sự cố này:

nhập mô tả hình ảnh ở đây

Điều này không nhất thiết là an toàn, vì vậy đây là một phương pháp có thể ngăn ngừa sự cố trong trường hợp bạn không chắc chắn về loại và giá trị:

Phương pháp 2 và ba biện pháp bảo vệ chống lại vấn đề này.

2) Tùy chọn hoàn toàn không bị ràng buộc

 if let unwrappedAge = age {

 // continue in here

 }

Lưu ý rằng loại chưa mở bây giờ là Int , chứ không phải Int? .

3) Tuyên bố bảo vệ

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

Từ đây, bạn có thể tiếp tục và sử dụng biến không được bao bọc. Hãy chắc chắn rằng chỉ buộc unsrap (với một!), Nếu bạn chắc chắn về loại biến.

Chúc may mắn với dự án của bạn!


1

Khi tôi bắt đầu tìm hiểu Swift, rất khó để nhận ra tại sao không bắt buộc .

Hãy suy nghĩ theo cách này. Hãy xem xét một lớp Personcó hai tài sản namecompany.

class Person: NSObject {

    var name : String //Person must have a value so its no marked as optional
    var companyName : String? ///Company is optional as a person can be unemployed that is nil value is possible

    init(name:String,company:String?) {

        self.name = name
        self.companyName = company

    }
}

Bây giờ hãy tạo một vài đối tượng Person

var tom:Person = Person.init(name: "Tom", company: "Apple")//posible
var bob:Person = Person.init(name: "Bob", company:nil) // also Possible because company is marked as optional so we can give Nil

Nhưng chúng ta không thể vượt qua Nilđểname

var personWithNoName:Person = Person.init(name: nil, company: nil)

Bây giờ hãy nói về lý do tại sao chúng ta sử dụng optional?. Hãy xem xét một tình huống mà chúng tôi muốn thêm Incsau tên công ty applesẽ như thế nào apple Inc. Chúng tôi cần phải nối Incsau tên công ty và in.

print(tom.companyName+" Inc") ///Error saying optional is not unwrapped.
print(tom.companyName!+" Inc") ///Error Gone..we have forcefully unwrap it which is wrong approach..Will look in Next line
print(bob.companyName!+" Inc") ///Crash!!!because bob has no company and nil can be unwrapped.

Bây giờ hãy nghiên cứu tại sao tùy chọn diễn ra.

if let companyString:String = bob.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.

    print(companyString+" Inc") //Will never executed and no crash!!!
}

Hãy thay thế bobbằngtom

if let companyString:String = tom.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.

    print(companyString+" Inc") //Will never executed and no crash!!!
}

chúc mừng! chúng tôi đã giải quyết đúng đắnoptional?

Vì vậy, các điểm thực hiện là

  1. Chúng tôi sẽ đánh dấu một biến là tùy chọn nếu có thể nil
  2. Nếu chúng ta muốn sử dụng biến này ở đâu đó trong trình biên dịch mã sẽ nhắc nhở bạn rằng chúng ta cần kiểm tra xem chúng ta có xử lý đúng với biến đó hay không nếu nó chứa nil.

Cảm ơn bạn ... Mã hóa hạnh phúc


0

Hãy thử nghiệm với mã dưới đây Playground. Tôi hy vọng sẽ rõ ý tưởng nào là tùy chọn và lý do sử dụng nó.

var sampleString: String? ///Optional, Possible to be nil

sampleString = nil ////perfactly valid as its optional

sampleString = "some value"  //Will hold the value

if let value = sampleString{ /// the sampleString is placed into value with auto force upwraped.

    print(value+value)  ////Sample String merged into Two
}

sampleString = nil // value is nil and the

if let value = sampleString{

    print(value + value)  ///Will Not execute and safe for nil checking
}

//   print(sampleString! + sampleString!)  //this line Will crash as + operator can not add nil

0

Từ https://developer.apple.com/lvern/content/documentation/Swift/Conceptual/Swift_Programming_Lingu/OptionalChained.html :

Chuỗi tùy chọn là một quá trình để truy vấn và gọi các thuộc tính, phương thức và đăng ký trên một tùy chọn hiện có thể là không. Nếu tùy chọn chứa một giá trị, thuộc tính, phương thức hoặc lệnh gọi đăng ký thành công; nếu tùy chọn là nil, thuộc tính, phương thức hoặc lệnh gọi đăng ký trả về nil. Nhiều truy vấn có thể được nối lại với nhau và toàn bộ chuỗi không thành công nếu bất kỳ liên kết nào trong chuỗi không.

Để hiểu sâu hơn, đọc liên kết ở trên.


0

Tốt...

? (Tùy chọn) cho biết biến của bạn có thể chứa giá trị không trong khi ! (unsrapper) cho biết biến của bạn phải có bộ nhớ (hoặc giá trị) khi nó được sử dụng (đã cố gắng lấy giá trị từ nó) khi chạy.

Sự khác biệt chính là chuỗi tùy chọn không thành công một cách duyên dáng khi tùy chọn là không, trong khi bắt buộc hủy kích hoạt sẽ gây ra lỗi thời gian chạy khi tùy chọn là không.

Để phản ánh thực tế rằng chuỗi kết nối tùy chọn có thể được gọi trên một giá trị không, kết quả của một cuộc gọi chuỗi tùy chọn luôn luôn là một giá trị tùy chọn, ngay cả khi thuộc tính, phương thức hoặc chỉ mục bạn đang truy vấn trả về giá trị không có giá trị. Bạn có thể sử dụng giá trị trả về tùy chọn này để kiểm tra xem cuộc gọi chuỗi tùy chọn có thành công hay không (tùy chọn được trả về có chứa giá trị) hoặc không thành công do giá trị không trong chuỗi (giá trị tùy chọn được trả về là không).

Cụ thể, kết quả của một cuộc gọi chuỗi tùy chọn có cùng loại với giá trị trả về dự kiến, nhưng được gói trong một tùy chọn. Một thuộc tính thường trả về một Int sẽ trả về một Int? khi truy cập thông qua chuỗi tùy chọn.

var defaultNil : Int?  // declared variable with default nil value
println(defaultNil) >> nil  

var canBeNil : Int? = 4
println(canBeNil) >> optional(4)

canBeNil = nil
println(canBeNil) >> nil

println(canBeNil!) >> // Here nil optional variable is being unwrapped using ! mark (symbol), that will show runtime error. Because a nil optional is being tried to get value using unwrapper

var canNotBeNil : Int! = 4
print(canNotBeNil) >> 4

var cantBeNil : Int = 4
cantBeNil = nil // can't do this as it's not optional and show a compile time error

Dưới đây là hướng dẫn cơ bản chi tiết, bởi Ủy ban nhà phát triển Apple: Chuỗi tùy chọn



-1

Đây là một tuyên bố tùy chọn tương đương trong Swift:

var middleName: String?

Khai báo này tạo ra một biến có tên middleName của kiểu String. Dấu hỏi (?) Sau loại biến Chuỗi cho biết biến middleName có thể chứa giá trị có thể là Chuỗi hoặc nil. Bất cứ ai nhìn vào mã này ngay lập tức đều biết rằng middleName có thể là con số không. Đó là tài liệu tự!

Nếu bạn không chỉ định giá trị ban đầu cho hằng số hoặc biến tùy chọn (như được hiển thị ở trên), giá trị sẽ tự động được đặt thành không cho bạn. Nếu bạn thích, bạn có thể đặt giá trị ban đầu thành nil:

var middleName: String? = nil

để biết thêm chi tiết cho tùy chọn đọc bên dưới liên kết

http://www.iphonelife.com/blog/31369/swift-101-usiness-swifts-new-optional-values


sử dụng cái này, var middleName: String! = ""
Gaurav
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.