Jaki jest symbol podkreślenia _ w Swift References?

144

W sekcji referencyjnej dokumentacji firmy Apple znajduje się wiele przykładów tego rodzaju rzeczy:

func runAction(_action: SKAction!)

`` Ekwiwalentem '' celu-C tego jest:

- (void)runAction:(SKAction *)action

Uderza mnie, że prawdopodobnie ważne jest, aby (w odwołaniu do języka Swift) była spacja po podkreśleniu i napisie „akcja” kursywą.

Ale nie potrafię zrozumieć, co to próbuje przekazać. Może więc pytanie brzmi ... czy istnieje odniesienie do konwencji użytych w odniesieniach?

- oto strona, do której odwołuję się w tym odwołaniu do użycia podkreślenia: https://developer.apple.com/documentation/spritekit/sknode#//apple_ref/occ/instm/SKNode/runAction

Aktualizacja

Swift 3 wprowadził pewne zmiany w sposobie używania i nazywania nazw parametrów funkcji / metod oraz etykiet argumentów. Ma to konsekwencje dla tego pytania i odpowiedzi. @Rickster wykonuje niesamowitą robotę, odpowiadając na inne pytanie dotyczące _podstawowych wyników w funkcjach, które w większości wyjaśniają ten problem, tutaj: Dlaczego potrzebuję szybko podkreślenia?

zmieszany
źródło
3
Oznaczone tagiem [underscore.js] ??
Martin R
3
Dokumentacja jest zgodna z matematyczną konwencją używania kursywy dla nazw zmiennych. Na przykład: sin² a + cos² a = 1.
rob mayoff

Odpowiedzi:

116

Obie odpowiedzi były poprawne, ale chcę wyjaśnić trochę więcej.

_służy do modyfikowania zachowania nazwy parametru zewnętrznego dla metod .

W sekcji Lokalne i zewnętrzne nazwy parametrów dla metod w dokumentacji jest napisane:

Swift domyślnie nadaje pierwszemu parametrowi w metodzie nazwę parametru lokalnego, a drugiemu i kolejnym nazwom parametrów zarówno lokalne, jak i zewnętrzne nazwy parametrów .

Z drugiej strony funkcje domyślnie nie mają nazw parametrów zewnętrznych.

Na przykład mamy tę foo()metodę zdefiniowaną w klasie Bar:

class Bar{
    func foo(s1: String, s2: String) -> String {
        return s1 + s2;
    }
}

Kiedy dzwonisz foo(), nazywa się to jak bar.foo("Hello", s2: "World").

Ale można to zmienić za pomocą _przed s2gdzie jest zadeklarowana.

func foo(s1: String, _ s2: String) -> String{
    return s1 + s2;
}

Następnie, kiedy wywołujesz foo, może być po prostu wywołane jak bar.foo("Hello", "World")bez nazwy drugiego parametru.

Wracając do twojego przypadku, runActionto metoda, ponieważ jest SKNodeoczywiście związana z typem . Zatem umieszczenie _parametru przed actionpozwala na wywołanie runActionbez nazwy zewnętrznej.

Aktualizacja dla Swift 2.0

Funkcja i metoda działają teraz w ten sam sposób, jeśli chodzi o deklarację nazwy argumentu lokalnego i zewnętrznego.

Funkcje są teraz wywoływane domyślnie przy użyciu nazwy parametru zewnętrznego, począwszy od drugiego parametru. Ta zasada dotyczy tylko czystego kodu Swift.

Tak więc, dostarczając _przed funkcją funkcję , wywołujący nie będzie musiał określać nazwy parametru zewnętrznego, tak jak zrobiłbyś to dla metody .

Aaron He
źródło
9
Zdezorientowany, jeśli _napiszesz przed drugim parametrem, twoja odpowiedź jest wystarczająco jasna; co jeśli w func runAction(_action: SKAction!), _jest przed pierwszym parametrem lub jeśli napiszesz następujący kod, func foo(_ s1: String) { // your code }Xcode dałoby ostrzeżenie, ale jest dużo kodu, jak func bringSubviewToFront(_ view: UIView)w referencji, dlaczego?
Will Zhang,
10
więc w zasadzie robi to bez powodu i po prostu dezorientuje wszystkich. niesamowite.
botbot
2
Podkreślenie jest znane jako „wzorzec wieloznaczny” developer.apple.com/library/ios/documentation/Swift/Conceptual/…
user2143356
@Wyatt Zhang, jak mówi dokument, użycie _pierwszego parametru jest obce. Mogę założyć, że projektanci uważają, że jest to oczywiście wystarczające dla twojego kodu i nie poprawia czytelności, wręcz przeciwnie, brudzi kod. Więc dostajesz ostrzeżenie. Odniesienie ma odwrotny cel: musi być tak jasne, jak to tylko możliwe - dlatego podkreślenie pierwszego parametru jest wspomniane dla KAŻDEJ metody. To by wszystko wyjaśniało)
Dmitry Gryazin
4
Należy zauważyć, że Swift 3.0 zmienia rzeczy. Wszystkie etykiety są wymagane, chyba że określono inaczej. Zatem -przed pierwszym parametrem nie jest już zbędny. Na przykład: override func viewWillAppear(_ animated: Bool)sygnalizuje, że dzwoniący (kod Objective-C) nie będzie używał etykiety parametru
Mr.T
85

Podkreślenie to ogólny token używany do wskazania odrzuconej wartości.

W tym konkretnym przypadku oznacza to, że funkcja zostanie wywołana jako runAction(argument)zamiastrunAction(action:argument)

W innych kontekstach ma inne podobne znaczenie, np. W:

for _ in 0..<5 { ... }

Oznacza to, że chcemy po prostu wykonać blok 5 razy i nie obchodzi nas indeks w bloku.

W tym kontekście:

let (result, _) = someFunctionThatReturnsATuple()

Oznacza to, że nie obchodzi nas, jaki jest drugi element krotki, tylko pierwszy.

David Berry
źródło
Czyli w tym przypadku argument (akcja) jest opcją?
Zmieszany
1
Nie, powoduje to, że nazwa parametru zewnętrznego (akcja :) w tym przypadku jest pusta, a tym samym pomijana. Argument jest nadal wymagany, po prostu nie jest oznaczony akcją :.
David Berry
4
Prawdziwa odpowiedź to połączenie odpowiedzi @ dasblinkenlight i mojej. Bardziej precyzyjnie odnosi się do tego konkretnego przypadku, podczas gdy mój dotyczy szerszego pytania, co oznacza _?
David Berry
4
Możesz użyć znaku odrzucenia również w przypadku bardzo dużych liczb, aby były bardziej czytelnelet pi = 3.141_592_653_59
SMP,
co zabawne, możesz go również użyć do uczynienia bardzo dużych liczb mniej czytelnymi, na przykładlet pi = 3.1_4_15_92___63
David Berry,
15

Od wersji Swift 3 wszystkie etykiety argumentów są domyślnie wymagane .

Możesz wymusić na IDE ukrycie etykiety argumentu za pomocą _.

func foo(a: String) {
}

func foo2(_ a: String) {
}

zadzwonił foo(a: "abc")ifoo2("abc")

Uwaga: To może być stosowany tylko wtedy, gdy ajest etykieta (zewnętrzne) Argument i (wewnętrzne) Nazwa zmiennej w tym samym czasie. Jest równoważne - func foo(a a: String)nie zaakceptuje _.

Dlaczego Apple go używa?

Możesz zobaczyć, że Apple używa go w całym interfejsie API. Biblioteki Apple są nadal napisane w Objective-C (jeśli nie, i tak mają te same nazwy funkcji, które zostały zaprojektowane dla składni Objective-C)

Funkcje takie jak applicationWillResignActive(_ application: UIApplication)miałyby redundantną nazwę parametru application, ponieważ w ich nazwie jest już aplikacja .

Twój przykład

func runAction(_ action: SKAction!)byłby nazywany bez swojego _znaku runAction(action:). Nazwa parametru actionbyłaby zbędna, ponieważ istnieje już w nazwie funkcji. To jest cel i dlaczego tam jest.

Jakub Truhlář
źródło
13

Identyfikator przed deklaracją parametru definiuje nazwę parametru zewnętrznego . To jest nazwa, którą musi podać dzwoniący podczas wywoływania funkcji:

func someFunction(externalParameterName localParameterName: Int)

Swift zapewnia automatyczną nazwę zewnętrzną dla każdego zdefiniowanego parametru domyślnego, jeśli sam nie podasz nazwy zewnętrznej. Użycie podkreślenia dla nazwy parametru zewnętrznego wyklucza to zachowanie:

Możesz zrezygnować z tego zachowania, wpisując podkreślenie ( _) zamiast jawnej nazwy zewnętrznej podczas definiowania parametru.

Możesz przeczytać więcej o tym zachowaniu w sekcji Nazwy zewnętrzne dla parametrów z wartościami domyślnymi tutaj .

dasblinkenlight
źródło
więc ... pozwól mi zobaczyć, czy moja tępota ma rację. W tym przykładzie powinienem nazwać zmienną / stałą mojego parametru jako „akcja” i przypisać ją do SKAction, którą chcę uruchomić za pomocą tej funkcji, a Swift automatycznie nazywa wymagany domyślny parametr „akcja”. JEDNAK, jeśli chcę niestandardowo nazwać tę akcję, muszę użyć podkreślenia w wywołaniu funkcji?
Zmieszany
4
@Confused Rozumiem, że SKprojektanci nie chcą, abyś pisał actiondwa razy, ponieważ „akcja” jest już częścią nazwy funkcji. Innymi słowy, nie chcą, żebyś pisał sprite.runAction(action:moveGroundSpritesForever). Celem nazw parametrów zewnętrznych było sprawienie, aby twój kod "czytał jak zdanie"; actiondwukrotne użycie zniweczyłoby cel tego.
dasblinkenlight
W ciemności zapaliło się kilka świateł. Myślę, że rozumiem. Ta cecha języka ma na celu sprawienie, że wywołanie funkcji w Swift będzie wyglądać podobnie do wywołania metody z parametrami w Objective-C. Może.
Zmieszany
1
Jednak podkreślenia można użyć, aby w jakiś sposób zrezygnować z posiadania tych zewnętrznych nazw parametrów dla parametrów zdefiniowanych z wartością domyślną ... po prostu jeszcze nie widziałem, jak to się robi. Będę szukał dalej.
Zmieszany
Więc ... w skrócie, po prostu przełącza się między parametrami nazwanymi a parametrami porządkowymi, dzięki czemu można łatwo przełączać się między foo.bar(param: 'fiddle') i foo.bar('fiddle') UWAGA: przy tylko jednym argumencie to naprawdę nie staje się oczywiste ... ale przy wielu argumentach staje się bardzo istotne: foo.bar(param1: 'fiddle', param2: 'dee') vs foo.bar('fiddle','dee')
jrypkahauer
10

Myślę, że wymusza to w Swifcie konwencję, która przybliża go do celu-c, co lepiej pasuje do konwencji kakaowych. W objc nie podajesz (zewnętrznie) nazwy swojego pierwszego parametru. Zamiast tego, zgodnie z konwencją, zwykle umieszcza się nazwę zewnętrzną w drugiej części nazwy metody w następujący sposób:

- (void)myFancyMethodWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName;

[someInstance myFancyMethodWithFirstName:@"John" lastName:@"Doe"];

Aby wywołania Swift api były spójne z objc, będziesz chciał pominąć nazwę parametru zewnętrznego pierwszego parametru.

func myFancyMethodWithFirstName(_ firstName:String, lastName:String);

someInstance.myFancyMethodWithFirstName("John", lastName:"Doe")
smileBot
źródło
2
Podoba mi się to wyjaśnienie. nauczyłeś się najpierw Obj-C, więc wszystko wyjaśniłeś. Podkreśla również znaczenie odpowiedniego nazwania metody w języku Swift, a mianowicie, druga część nazwy metody powinna opisywać pierwszy argument, jak to zwykle ma miejsce w Obj-C. dobry towar.
rrrrrraul
5

W rzeczywistości istnieje różnica między rzeczywistym kodem używanym do zdefiniowania metody a deklaracją metody w dokumentacji Apple. Weźmy UIControl „s - addTarget: Działanie: forControlEvents: Sposób na przykład, prawdziwy kod jest: wprowadź opis obrazu tutaj

Ale w dokumentach wygląda to tak (uwaga _ przed celem): wprowadź opis obrazu tutaj

W prawdziwym kodzie _ służy do tego, aby zewnętrzna nazwa drugiego lub kolejnego parametru nie pojawiała się po wywołaniu metody, podczas gdy w dokumentach _ przed lokalną nazwą parametru wskazuje, że kiedy wywołujesz metodę lub funkcję, nie powinieneś podawać nazwa zewnętrzna.

Nie ma nazwy zewnętrznej, gdy funkcja jest wywoływana domyślnie, chyba że podasz własną lub dodasz # przed (bez spacji) lokalną nazwę parametru, na przykład, tak używamy dispatch_after : wprowadź opis obrazu tutaj

W dokumentach wygląda to tak (zwróć uwagę na trzy _): wprowadź opis obrazu tutaj

Konwencja deklaracji funkcji jest taka sama, jak opisałem dla metody.

fujianjin6471
źródło
1

Tylko bardziej wizualnie.

wprowadź opis obrazu tutaj

Jak widać, po _prostu make pomija lokalną nazwę parametru lub nie.

Nik Kov
źródło