2016-04-03 77 views
2

我瞭解String!類型和String?類型之間的區別。但String類型呢?它與String!String?在swift中有什麼不同? String!類型與String類型相同嗎?關於Swift中的變量類型

說,我有一類這樣的:

class Person { 
    private var _name: String! 

    var name: String { 
     return _name 
    } 

    init(name: String) { 
    _name = name 
    } 
} 

沒有編譯器錯誤,貌似String類型是相同的String!型。但我不確定...

回答

1

StringString!是相同和不同的在同一時間。如果您將let或var聲明爲String,則必須在init方法中設置一些值。如果您將其聲明爲String!,則可以在需要時設置值,但必須在讀取此值之前進行設置。

因此,如果您的_name將是nil,您的應用程序將崩潰。

如果將其聲明爲String,則編譯器會在第一次讀取前保證_name != nil。如果你聲明它爲String!,你應該保證它。

這東西有相同類型的,因爲這樣的:

var test1: String = "test" 
var test2: String! = "test" 

if test1 is String { // True 
    print("test1 is String") 
} 
if test2 is String { // True 
    print("test2 is String") 
} 

此類型相同,但這個東西是不同的

+2

'String'和''字符串不相等本身,他們有一些細微的差別!後者是一個'ImplicitlyUnwrappedOptional'封裝'String',即使它是「隱式解開」,你可以使用例如一個條件綁定塊中的'String!'實例('如果let foo = bar {'''bar'是類型'String!'),而您可能不會用於「純」字符串實例。然而,他們確實有許多相似之處,然而例如安全不是其中之一。 – dfri

+0

@Artyom,根據你的說明,是否最好用'String'類型而不是'String!'聲明'_name',這樣編譯器總是會提醒我在'init'中設置一個值,我的應用程序的崩潰機率會降低,否則,如果像我現在所做的那樣,'_name'是'String!'類型的,我可以得到一個零值並意外崩潰我的應用程序? –

+0

@ Leem.fin你不能初始化你的例子類沒有名字,但你可以設置爲零後名稱,它可以導致崩潰,如果你的變量將被訪問 –

0

你是更好的閱讀swift documentation比這裏的任何答覆。適當的undestandig swift的類型系統非常重要,所以先做。

-1

都是String!String?是可選類型。

使用String?需要您測試值是否爲(.None)或值(.Some)。例如使用警戒語句或if-let子句。

String!是一個可選項,假定爲非零並自動解包。這使您可以編寫看起來更清晰的代碼,並避免在使用任何值的情況下解包。但是:如果您的值是將發生致命錯誤。

+1

這將在Swift 3中成立,但在2.2中並非如此。 'String!'是'ImplicitlyUnwrappedOptional ',它是'Optional '的另一種類型。 –

+0

是_ImplicitlyUnwrappedOptional_ _Optional_的子類型? – nielsbot

+0

不可以。您不能擁有枚舉的子類型。 –

4

StringString!不完全相同。在這種語言中恰好有足夠的糖來轉換它們。類似地,在語言中有糖可以在StringString?之間轉換(但不能反向)。

從基礎開始。有String。除非有很強的理由,否則當您指的是一串字符時,應該使用String。其他一切都是「更多的東西」,除非你需要它,否則不應該添加它。

Optional<String>。這只是兩種情況,一種具有價值,一個沒有價值的枚舉:

public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible { 
    case None 
    case Some(Wrapped) 
    // ... 
} 

沒有爲Optional後綴運算符!將返回Wrapped如果它是可用的,並且崩潰,如果事實並非如此。到目前爲止,沒有魔法。這是你可以建立自己的東西。

Optional附近有幾塊魔法。首先,編譯器將Wrapped?類型神奇地轉換爲Optional<Wrapped>(對於任何Wrapped)。這只是句法糖。這兩個符號是相同的。其次,可以選擇與「運營商」鏈接(它不是真正的運營商;它是語言的一部分,您無法自己構建它)。然後有可選的促銷。如果需要,任何類型的Wrapped都可以自動和隱式轉換爲Wrapped?。在Optional之前還有其他一些魔法,比如if-let的語法,還有nil這是Optional.None(我相信它們實際上是相同的)的同義詞。但Optional真的只是一個通用類型,實現爲枚舉。這只是編譯器知道特殊情況的一種類型。

然後有ImplicitlyUnwrappedOptional<Wrapped>。這也只是一個枚舉(在Swift 2.2中;這將在Swift 3中改變)。

public enum ImplicitlyUnwrappedOptional<Wrapped> : _Reflectable, NilLiteralConvertible { 
    case None 
    case Some(Wrapped) 
    // ... 
} 

這是不一樣的Optional,這是不一樣的Wrapped。這是完全不同的類型。但它也有一些相關的魔力。首先,類型Wrapped!是語法糖ImplicitlyUnwrappedOptional<Wrapped>。再次,它只是糖。兩者是相同的(在Swift 2.2中,不在Swift 3中)。接下來,如果在Wrapped預計會發現IUO<Wrapped>,它將自動轉換爲Wrapped或在沒有值的情況下崩潰。如果在Wrapped?的地方發現它,它會自動轉換爲Wrapped?。這些都是神奇的,這就是爲什麼有時StringString!似乎是相同的類型。這只是編譯器通過添加一個不可見的轉換步驟而神奇地「爲它工作」。這並不意味着它們真的是同一類型的。

IUO主要用於橋接某些Objective-C模式,特別是涉及故事板,並且應該避免出現這些情況。即使在這些情況下,IUO也只是爲了方便。你可以使用普通的Optionals完成所有相同的事情,你只需要更頻繁地使用if-let來檢查它們。使用Optionals比使用IUO更安全。很容易想到「我知道這個值在使用之前總會被設置。」就在這個星期,我因爲錯誤而追趕了一個不速之客。 「它應該」和「它一定是」有區別。但是,使用Storyboard中的Optionals完全安全可能會非常不方便,並且可能會掩蓋一些錯誤(不做任何事情而不是崩潰),所以這是IUO最常見的地方。

IUO屬性過去對處理failable init方法有價值。這在Swift 2.2中不再是問題,因此使用已經消失。我遇到的最後一個「純Swift」用法是當你必須將self傳遞給你作爲屬性存儲的東西的初始值設定項時(因爲所有的屬性都已經初始化,所以你不能通過self)。這是一個不幸的用例,非常混亂,我希望我們能爲它提供一個解決方案。在這些情況之外,您應該避免隱式解包選項。

1

注意這兩個函數的區別是:

func f() { 
    let x: String? = nil 
    guard let y: String = x else { 
     print("failed") 
     return 
    } 
} 

func g() { 
    let x: String? = nil 
    guard let y: String! = x else { 
     print("failed") 
     return 
    } 
    print(y.dynamicType, y) 
} 

f() # failed 
g() # Optional<String> nil 
+2

這是一個非常有趣的角落案例,但可能比它更令人迷惑(它甚至可能是一個編譯器錯誤,儘管如此,它將在Swift 3中無關緊要)。輸出結果表明'String!'和'String?'是相同的類型,但這不是發生了什麼。我確定'guard-let'正在將'x'提升爲'String ??',這是它成功的原因。提升的'String ??'有一個值;該值是'.Some(nil)'(它與'nil'完全不同)。比較你的例子和這個更簡單的例子:'let x:String? =無;讓z:String! = x;打印(z.dynamicType)'。 –

+1

@RobNapier我確實認爲這是一個編譯器bug,它限於在'let let'和'guard let'子句'中顯式聲明綁定爲'ImplicitlyUnwrappedOptional '的類型,正如我之前在[本線程] //stackoverflow.com/questions/36304448/optional-binding-to-an-immutable-explicitly-declared-to-be-of-type-implicitlyun)。 Bug報告已經提交[這裏(SR-1123)](https://bugs.swift.org/browse/SR-1123),但正如你所說,它應該不相關(並且已經隱式修正:)在Swift中3。 – dfri