2016-08-01 7 views
14

Z opcjonalnym łańcuchowych, jeśli mam Swift zmiennąOpcjonalnie łańcuchowym z Swift ciągów

var s: String? 

s może zawierać zero lub ciąg znaków zawinięty w opcjonalnym. Tak, próbowałem to aby uzyskać jego długość:

let count = s?.characters?.count ?? 0 

Jednak kompilator chce w ten sposób:

let count = s?.characters.count ?? 0 

Moje rozumienie opcjonalnym łańcuchowych jest, że po rozpoczęciu korzystania ?. w przerywaną wypowiedzi, pozostałe właściwości są opcjonalne i są zwykle dostępne przez ?., a nie ..

Więc wykopał trochę dalej i próbował tego na boisku:

var s: String? = "Foo" 
print(s?.characters) 
// Output: Optional(Swift.String.CharacterView(_core: Swift._StringCore(_baseAddress: 0x00000001145e893f, _countAndFlags: 3, _owner: nil))) 

Wynik wskazuje, że s?.characters jest rzeczywiście Opcjonalnie instancji, wskazując, że s?.characters.count powinno być nielegalne.

Czy ktoś może mi pomóc zrozumieć ten stan rzeczy?

+1

Zarówno 's? .characters.count', jak i' (s? .characters)? Count' kompilują się, ale '(s? .characters) .count' does not. Wygląda na to, że 'characters.count' jest traktowany jak pojedyncze opcjonalne połączenie w pierwszym przypadku, ale nie widziałem tego udokumentowanego. –

+0

Omówiono również teraz na temat [szybkich użytkowników]: https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160801/002764.html. –

Odpowiedz

5

Kiedy mówisz:

Moje rozumienie opcjonalnym łańcuchowych jest, że gdy zaczniesz używać ?. w przerywaną wypowiedzi, reszta właściwości są opcjonalne i są zazwyczaj dostępne przez ?., nie ..

Powiedziałbym, że już prawie jesteś.

Nie wszystkie właściwości są opcjonalne, ponieważ oryginalne połączenie jest opcjonalne, więc wygląda na to, że inne właściwości są opcjonalne.

characters nie jest właściwością opcjonalną, ani nie jest count, ale wartość, do której ją wywołujesz, jest opcjonalna. Jeśli istnieje wartość, właściwości characters i count zwrócą wartość; w przeciwnym razie zwracana jest nazwa nil. Z tego powodu wynik s?.characters.count zwraca wartość Int?.

Jeśli którakolwiek z właściwości była opcjonalna, musisz dodać do niej ?, ale w twoim przypadku tak nie jest. A więc nie.


Zmieniano następujący komentarz

Z komentarza:

I jeszcze znaleźć to dziwne, że zarówno s?.characters.count i (s?.characters)?.count kompilacji, ale (s?.characters).count nie. Dlaczego występuje różnica między pierwszym a ostatnim wyrażeniem?

Spróbuję odpowiedzieć na to tutaj, gdzie jest więcej miejsca niż w polu komentarza:

s?.characters.count 

Jeśli s jest zerowa, całe wyrażenie zwraca nil, w przeciwnym razie Int. Tak więc typem zwrotu jest Int?.

(s?.characters).count // Won’t compile 

Złamanie tego dół: jeśli s jest nil, następnie (s?.characters) jest nil, więc nie możemy nazwać count na nim.

W celu wywołania właściwości count na (s?.characters) wyrażenie musi być opcjonalnie odwinął, czyli zapisać jako:

(s?.characters)?.count 

Edited by dodać dalsze

najlepiej jak potrafię wyjaśnienie tego jest z tym trochę kodu zabawowego:

let s: String? = "hello" 

s?.characters.count 
(s?.characters)?.count 
(s)?.characters.count 
((s)?.characters)?.count 

// s?.characters.count 
func method1(s: String?) -> Int? { 
    guard let s = s else { return nil } 

    return s.characters.count 
} 

// (s?.characters).count 
func method2(s: String?) -> Int? { 
    guard let c = s?.characters else { return nil } 

    return c.count 
} 

method1(s) 
method2(s) 
+0

Nadal uważam za dziwne, że oba 's? .characters.count' i' (s ?.znaków). count 'compile, ale' (s? .characters) .count' does not. Dlaczego występuje różnica między pierwszym a ostatnim wyrażeniem? –

+0

W '(s? .characters) .count' spróbujesz uzyskać właściwość' count' opcji opcjonalnej. W pierwszym "znaki" nie jest opcjonalne. –

+0

@MartinR Próbowałem odpowiedzieć na to w edytowanej odpowiedzi. – Abizern

2

sprawie szybkiej użytkownikami listy, Ingo Maier był na tyle uprzejmy, żeby wskazać mi do section on optional chaining expressions w Swift specyfikacji języka, który stanowi:

Jeśli wyrażenie postfix który zawiera opcjonalną-łańcuchowym wyrażenie jest zagnieżdżony wewnątrz innych wyrażeń postfiksowych, tylko najbardziej zewnętrzne wyrażenie zwraca typ opcjonalny.

Kontynuuje na przykładzie:

var c: SomeClass? 
var result: Bool? = c?.property.performAction() 

To wyjaśnia, dlaczego kompilator chce s .characters.count w moim przykładzie powyżej, uważam, że odpowiada na pierwotne pytanie. Jednak, jak @Martin R zaobserwowano w komentarzu, jest jeszcze tajemnicą, dlaczego te dwa wyrażenia są traktowane inaczej przez kompilator:

s?.characters.count 
(s?.characters).count 

Jeśli czytam spec poprawnie, podwyrażenie

(s?.characters) 

jest „zagnieżdżony” ogólnej ekspresji przyrostkiem

(s?.characters).count 

i powinny być traktowane tak samo jak w wersji nie nawiasach. Ale to oddzielny problem.

Dziękuję wszystkim za wkład!

+0

Jak wspomniano na liście, specyfikacja jest nieco pomijana w zakresie znaku zapytania, ale myślę, że swiftc robi to, co trzeba. W językach programowania dość często używa się nawiasów, aby ograniczyć zakres wszystkich rodzajów operatorów/słów kluczowych. Często prowadzi to do ładnej (powiedziałbym intuicyjnie) właściwości, którą można zastąpić wyrażeniami parentetyzowanymi za pomocą wiązań let i nadal mieć tę samą semantykę. Na przykładzie "let x = s? .characters; x? .count' ma taką samą semantykę jak '(s? .characters)? count', co nie byłoby możliwe, gdyby' (s? .characters) .count' był prawidłowym kodem Swift. – ingoem