Wofür steht der _ Unterstrich in Swift References?


144

Im Referenzabschnitt der Apple-Dokumente finden Sie viele Beispiele für solche Dinge:

func runAction(_action: SKAction!)

Das Objective-C-Äquivalent dazu ist:

- (void)runAction:(SKAction *)action

Es fällt mir auf, dass es wahrscheinlich wichtig ist, dass (in der Swift-Referenz) nach dem Unterstrich ein Leerzeichen steht und "Aktion" kursiv geschrieben ist.

Aber ich kann nicht herausfinden, was dies zu vermitteln versucht. Vielleicht ist die Frage ... gibt es eine Referenz für die Konventionen, die in den Referenzen verwendet werden?

- Hier ist die Seite, auf die ich in diesem Verweis auf die Verwendung des Unterstrichs verweise: https://developer.apple.com/documentation/spritekit/sknode#//apple_ref/occ/instm/SKNode/runAction

Aktualisieren

Swift 3 hat einige Änderungen an der Verwendung und Benennung von Funktions- / Methodenparameternamen und Argumentbezeichnungen vorgenommen. Dies hat Konsequenzen für diese Frage und ihre Antwort. @Rickster beantwortet auf erstaunliche Weise eine andere Frage zu _underscores in Funktionen, die viel davon klären. Hier: Warum brauche ich schnell Unterstriche?


3
Markiert mit [underscore.js] ??
Martin R

3
Die Dokumentation folgt der mathematischen Konvention, Kursivschrift für Variablennamen zu verwenden. Zum Beispiel: sin² a + cos² a = 1.
rob mayoff

Antworten:


116

Beide Antworten waren richtig, aber ich möchte etwas mehr klarstellen.

_wird verwendet, um das Verhalten externer Parameternamen für Methoden zu ändern .

Im Abschnitt Lokale und externe Parameternamen für Methoden der Dokumentation heißt es:

Swift gibt dem ersten Parameternamen in einer Methode standardmäßig einen lokalen Parameternamen und dem zweiten und den nachfolgenden Parameternamen standardmäßig sowohl lokale als auch externe Parameternamen .

Andererseits haben Funktionen standardmäßig keine externen Parameternamen.

Zum Beispiel haben wir diese foo()Methode in der Klasse definiert Bar:

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

Wenn Sie anrufen foo(), heißt es wie bar.foo("Hello", s2: "World").

Aber , können Sie dieses Verhalten außer Kraft setzen , indem Sie _vor , s2wo es erklärt.

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

Wenn Sie dann aufrufen foo, kann es einfach wie bar.foo("Hello", "World")ohne den Namen des zweiten Parameters aufgerufen werden.

Zurück zu Ihrem Fall, runActionist eine Methode, weil sie SKNodeoffensichtlich mit dem Typ verbunden ist. Wenn Sie also einen _before-Parameter actioneingeben, können Sie runActionohne externen Namen aufrufen .

Update für Swift 2.0

Funktion und Methode funktionieren jetzt in Bezug auf die Deklaration lokaler und externer Argumentnamen auf dieselbe Weise .

Funktionen werden jetzt standardmäßig mit einem externen Parameternamen aufgerufen, beginnend mit dem 2. Parameter. Diese Regel gilt nur für reinen Swift-Code.

Wenn Sie also _eine Funktion vor einer Funktion bereitstellen , muss der Aufrufer keinen externen Parameternamen angeben, wie Sie es für eine Methode tun würden .


9
Verwirrt, wenn Sie _vor dem zweiten Parameter schreiben, ist Ihre Antwort eindeutig genug; Was ist, wenn in func runAction(_action: SKAction!), das _vor dem ersten Parameter steht oder wenn Sie den folgenden Code schreiben ? func foo(_ s1: String) { // your code }Xcode würde Ihnen eine Warnung geben, aber es gibt viel Code wie func bringSubviewToFront(_ view: UIView)in der Referenz, warum?
Will Zhang

10
Im Grunde tut es dies ohne Grund und verwirrt nur alle. genial.
Botbot

2
Ein Unterstrich ist als "Wildcard Pattern" bekannt. Developer.apple.com/library/ios/documentation/Swift/Conceptual/…
user2143356

@ Wyatt Zhang, sagt der Arzt, dass die Verwendung _für den ersten Parameter irrelevant ist. Ich kann davon ausgehen, dass die Designer der Meinung sind, dass dies offensichtlich für Ihren Code ausreicht und die Lesbarkeit nicht verbessert, im Gegenteil, es verschmutzt den Code. Sie erhalten also die Warnung. Die Referenz hat das entgegengesetzte Ziel: Sie muss so klar wie möglich sein - daher wird der Unterstrich des ersten Parameters für JEDE Methode erwähnt. Das würde alles erklären)
Dmitry Gryazin

4
Es ist wichtig zu beachten, dass Swift 3.0 Dinge ändert. Alle Etiketten sind erforderlich, sofern Sie nichts anderes angeben. Das -vor dem ersten Parameter ist also nicht mehr irrelevant. Zum Beispiel: override func viewWillAppear(_ animated: Bool)signalisiert, dass der Anrufer (Objective-C-Code) keine Parameterbezeichnung verwendet
Mr. T

85

Der Unterstrich ist ein allgemeines Token, mit dem ein verworfener Wert angegeben wird.

In diesem speziellen Fall bedeutet dies, dass die Funktion als runAction(argument)statt aufgerufen wirdrunAction(action:argument)

In anderen Zusammenhängen hat es eine andere ähnliche Bedeutung, z. B.:

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

Dies bedeutet, dass wir den Block lediglich fünfmal ausführen möchten und uns nicht um den Index innerhalb des Blocks kümmern.

In diesem Kontext:

let (result, _) = someFunctionThatReturnsATuple()

Es bedeutet, dass es uns egal ist, was das zweite Element des Tupels ist, nur das erste.


In diesem Fall ist das Argument (eine Aktion) also eine Option?
Verwirrt

1
Nein, der externe Parametername (Aktion :) wird in diesem Fall leer und daher weggelassen. Das Argument ist weiterhin erforderlich, es ist nur nicht mit action: gekennzeichnet.
David Berry

4
Die eigentliche Antwort ist eine Kombination aus der Antwort von @ dasblinkenlight und meiner. Er spricht diesen speziellen Fall genauer an, während meiner die umfassendere Frage anspricht, was bedeutet _?
David Berry

4
Sie können das Abwurfzeichen auch für sehr große Zahlen verwenden, um sie so besser lesbar zu machenlet pi = 3.141_592_653_59
SMP

Amüsanterweise können Sie es auch verwenden, um sehr große Zahlen weniger lesbar zu machen, wielet pi = 3.1_4_15_92___63
David Berry

15

Seit Swift 3 sind standardmäßig alle Argumentbezeichnungen erforderlich .

Sie können eine IDE zwingen, eine Argumentbezeichnung mit auszublenden _.

func foo(a: String) {
}

func foo2(_ a: String) {
}

genannt foo(a: "abc")undfoo2("abc")

Hinweis: Dies kann nur verwendet werden, wenn gleichzeitig adie (externe) Argumentbezeichnung und der (interne) Variablenname angegeben sind . Es ist gleichwertig - func foo(a a: String)wird das nicht akzeptieren _.

Warum verwendet Apple es?

Sie können sehen, dass Apple es über die API verwendet. Apples Bibliotheken sind immer noch in Objective-C geschrieben (wenn nicht, haben sie ohnehin dieselben Funktionsnamen, die für die Objective-C-Syntax entwickelt wurden).

Funktionen wie applicationWillResignActive(_ application: UIApplication)hätten einen redundanten Parameternamen application, da die Anwendung bereits im Funktionsnamen enthalten ist.

Dein Beispiel

func runAction(_ action: SKAction!)würde aufgerufen werden , ohne es der _Marke wie runAction(action:). Der Parametername actionwäre redundant, da der Funktionsname bereits einen enthält. Das ist der Zweck und warum es da ist.


13

Ein Bezeichner vor der Parameterdeklaration definiert einen externen Parameternamen. Dies ist der Name, den der Aufrufer beim Aufrufen der Funktion angeben muss:

func someFunction(externalParameterName localParameterName: Int)

Swift stellt einen automatischen externen Namen für jeden von Ihnen definierten Standardparameter bereit, wenn Sie selbst keinen externen Namen angeben. Wenn Sie einen Unterstrich für den externen Parameternamen verwenden, wird dieses Verhalten nicht berücksichtigt:

Sie können dieses Verhalten deaktivieren, _indem Sie beim Definieren des Parameters einen Unterstrich ( ) anstelle eines expliziten externen Namens schreiben .

Weitere Informationen zu diesem Verhalten finden Sie im Abschnitt Externe Namen für Parameter mit Standardwerten hier .


Also ... lass mich sehen, ob meine Schwachsinnigkeit das richtig gemacht hat. In diesem Beispiel sollte ich meine Parametervariable / Konstante als "Aktion" benennen und sie der SKAction zuweisen, die von dieser Funktion ausgeführt werden soll, und Swift benennt automatisch den erforderlichen Standardparameter "Aktion". Wenn ich diese Aktion jedoch benutzerdefinieren möchte, muss ich beim Aufrufen der Funktion den Unterstrich verwenden?
Verwirrt

4
@Confused Mein Verständnis ist, dass SKdie Designer nicht möchten, dass Sie actionzweimal schreiben , da "Aktion" bereits Teil des Funktionsnamens ist. Mit anderen Worten, sie wollen nicht, dass du schreibst sprite.runAction(action:moveGroundSpritesForever). Der Zweck externer Parameternamen bestand darin, Ihren Code "wie einen Satz lesen" zu lassen. actionzweimaliges Verwenden würde den Zweck davon zunichte machen.
Dasblinkenlight

In der Dunkelheit gingen einige Lichter an. Ich glaube ich verstehe. Diese Funktion der Sprache soll dazu führen, dass aufrufende Funktionen in Swift dem Aufrufen einer Methode mit Parametern in Objective-C sehr ähnlich sind. Vielleicht.
Verwirrt

1
Der Unterstrich kann jedoch verwendet werden, um zu verhindern, dass diese externen Parameternamen für Parameter mit einem Standardwert definiert werden. Ich habe nur noch nicht gesehen, wie das gemacht wird. Ich werde weiter suchen.
Verwirrt

Kurz gesagt, es wird einfach zwischen benannten und ordinalen Parametern umgeschaltet, sodass Sie leicht zwischen foo.bar(param: 'fiddle') und foo.bar('fiddle') wechseln können. HINWEIS: Mit nur einem Argument wird es wirklich nicht offensichtlich ... aber mit mehreren Argumenten wird es sehr relevant: foo.bar(param1: 'fiddle', param2: 'dee') vs. foo.bar('fiddle','dee')
Jrypkahauer

10

Ich denke, dies erzwingt eine Konvention in Swift, die es näher an Ziel-c bringt, was besser zu Kakaokonventionen passt. In objc benennen Sie Ihren ersten Parameter nicht (extern). Stattdessen fügen Sie gemäß Konvention normalerweise den externen Namen wie folgt in den letzten Teil des Methodennamens ein:

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

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

Um Swift-API-Aufrufe mit objc konsistent zu machen, sollten Sie den externen Parameternamen des ersten Parameters unterdrücken.

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

someInstance.myFancyMethodWithFirstName("John", lastName:"Doe")

2
Ich mag diese Erklärung. Nachdem Sie zuerst Obj-C gelernt haben, haben Sie die Dinge geklärt. Es wird auch hervorgehoben, wie wichtig es ist, die Methode in Swift angemessen zu benennen, dh der letzte Teil des Methodennamens sollte das erste Argument beschreiben, wie dies normalerweise in Obj-C der Fall ist. gutes Zeug.
rrrrrraul

5

Tatsächlich gibt es einen Unterschied zwischen dem tatsächlichen Code, der zum Definieren einer Methode verwendet wird, und der Methodendeklaration in Apples Dokumenten. Nehmen wir UIControl ‚s - addTarget: Aktion: forControlEvents: Verfahren zum Beispiel die echten Code ist: Geben Sie hier die Bildbeschreibung ein

In Dokumenten sieht es jedoch so aus (Hinweis _ vor dem Ziel): Geben Sie hier die Bildbeschreibung ein

Im realen Code wird _ verwendet, um den externen Namen des zweiten oder nachfolgenden Parameters beim Aufrufen einer Methode nicht anzuzeigen , während in docs _ vor dem lokalen Namen eines Parameters angegeben wird, dass Sie beim Aufrufen einer Methode oder einer Funktion keine angeben sollten externer Name.

Es gibt keinen externen Namen, wenn eine Funktion standardmäßig aufgerufen wird, es sei denn, Sie geben Ihren eigenen Namen an oder fügen # vor (ohne Leerzeichen) dem lokalen Namen eines Parameters hinzu. So verwenden wir beispielsweise dispatch_after : Geben Sie hier die Bildbeschreibung ein

Und in Dokumenten sieht es so aus (beachten Sie drei _): Geben Sie hier die Bildbeschreibung ein

Die Konvention der Funktionsdeklaration ist genau die gleiche, die ich für die Methode beschrieben habe.


1

Nur optisch.

Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen können, lassen Sie _einfach einen lokalen Parameternamen weg oder nicht.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.