Warum brauche ich schnell Unterstriche?

161

Hier heißt es: "Hinweis: Das _bedeutet" Dieser Wert ist mir egal ". Da ich jedoch aus JavaScript stamme, verstehe ich nicht, was das bedeutet.

Die einzige Möglichkeit, diese Funktionen zum Drucken zu bringen, bestand darin, die Unterstriche vor den Parametern zu verwenden:

func divmod(_ a: Int, _ b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

print(divmod(7, 3))
print(divmod(5, 2))
print(divmod(12,4))

Ohne die Unterstriche muss ich es so schreiben, um Fehler zu vermeiden:

func divmod(a: Int, b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

print(divmod(a: 7, b: 3))
print(divmod(a: 5, b: 2))
print(divmod(a: 12,b: 4))

Ich verstehe diese Verwendung nicht. Wann, wie und warum verwende ich diese Unterstriche?

Michael Rader
quelle

Antworten:

353

Es gibt einige Nuancen für verschiedene Anwendungsfälle, aber im Allgemeinen bedeutet ein Unterstrich "dies ignorieren".


Wenn Sie eine neue Funktion deklarieren, teilt ein Unterstrich Swift mit, dass der Parameter beim Aufruf keine Bezeichnung haben sollte - das ist der Fall, den Sie sehen. Eine vollständigere Funktionsdeklaration sieht folgendermaßen aus:

func myFunc(label name: Int) // call it like myFunc(label: 3)

"label" ist ein Argument label und muss vorhanden sein, wenn Sie die Funktion aufrufen. (Und seit Swift 3 sind standardmäßig Beschriftungen für alle Argumente erforderlich.) "Name" ist der Variablenname für das Argument, das Sie in der Funktion verwenden. Eine kürzere Form sieht folgendermaßen aus:

func myFunc(name: Int) // call it like myFunc(name: 3)

Dies ist eine Verknüpfung, mit der Sie dasselbe Wort sowohl für die externe Argumentbezeichnung als auch für den internen Parameternamen verwenden können. Es ist gleichbedeutend mit func myFunc(name name: Int).

Wenn Sie möchten, dass Ihre Funktion ohne Parameterbezeichnungen aufgerufen werden kann, verwenden Sie den Unterstrich _, damit die Bezeichnung nichts / ignoriert wird. (In diesem Fall müssen Sie einen internen Namen angeben, wenn Sie den Parameter verwenden möchten.)

func myFunc(_ name: Int) // call it like myFunc(3)

In einer Zuweisungsanweisung bedeutet ein Unterstrich "nichts zuweisen". Sie können dies verwenden, wenn Sie eine Funktion aufrufen möchten, die ein Ergebnis zurückgibt, sich aber nicht um den zurückgegebenen Wert kümmert.

_ = someFunction()

Oder, wie in dem Artikel, auf den Sie verlinkt haben, ein Element eines zurückgegebenen Tupels zu ignorieren:

let (x, _) = someFunctionThatReturnsXandY()

Wenn Sie einen Abschluss schreiben, der einen definierten Funktionstyp implementiert, können Sie den Unterstrich verwenden, um bestimmte Parameter zu ignorieren.

PHPhotoLibrary.performChanges( { /* some changes */ },
    completionHandler: { success, _ in // don't care about error
        if success { print("yay") }
    })

Ebenso, wenn die Deklaration eine Funktion , die ein Protokoll oder überschreibt eine übergeordnete Klasse Methode annimmt, können Sie _für die Parameternamen Parameter zu ignorieren. Da das Protokoll / die Oberklasse möglicherweise auch definiert, dass der Parameter keine Bezeichnung hat, können Sie sogar zwei Unterstriche hintereinander erhalten.

class MyView: NSView {
    override func mouseDown(with _: NSEvent) {
        // don't care about event, do same thing for every mouse down
    }
    override func draw(_ _: NSRect) {
        // don't care about dirty rect, always redraw the whole view
    }
}

Etwas verwandt mit den letzten beiden Stilen: Wenn Sie ein Flusssteuerungskonstrukt verwenden, das eine lokale Variable / Konstante bindet, können Sie diese _ignorieren. Wenn Sie beispielsweise eine Sequenz iterieren möchten, ohne Zugriff auf ihre Mitglieder zu benötigen:

for _ in 1...20 { // or 0..<20
    // do something 20 times
}

Wenn Sie Tupelfälle in einer switch-Anweisung binden, kann der Unterstrich wie in diesem Beispiel als Platzhalter fungieren (abgekürzt von einem in The Swift Programming Language ):

switch somePoint { // somePoint is an (Int, Int) tuple
case (0, 0):
    print("(0, 0) is at the origin")
case (_, 0):
    print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    print("(0, \(somePoint.1)) is on the y-axis")
default:
    print("(\(somePoint.0), \(somePoint.1)) isn't on an axis")
}

Eine letzte Sache , die nicht ganz verwandt ist, aber ich werde da sind (wie durch Kommentare vermerkt) scheint es hier Menschen führen: Ein Unterstrich in einem Bezeichner - zB var _foo, func do_the_thing(), struct Stuff_- Mittel nichts Bestimmtes zu Swift, aber hat ein paar Anwendungen unter Programmierern.

Unterstriche innerhalb eines Namens sind eine Stilwahl, werden jedoch in der Swift-Community nicht bevorzugt, die strenge Konventionen zur Verwendung von UpperCamelCase für Typen und LowerCamelCase für alle anderen Symbole hat.

Das Präfixieren oder Suffixieren eines Symbolnamens mit Unterstrich ist eine Stilkonvention, die in der Vergangenheit verwendet wurde, um Symbole für den privaten / internen Gebrauch von der exportierten API zu unterscheiden. Swift verfügt jedoch über Zugriffsmodifikatoren dafür, sodass diese Konvention in Swift im Allgemeinen als nicht idiomatisch angesehen wird.

In func __foo()den Tiefen von Apples SDKs lauern einige Symbole mit doppelten Unterstrichen ( ): Dies sind (Obj) C-Symbole, die mit dem NS_REFINED_FOR_SWIFTAttribut in Swift importiert wurden . Apple verwendet dies, wenn eine "schnellere" Version einer (Obj) C-API erstellt werden soll, um beispielsweise eine typunabhängige Methode in eine generische Methode umzuwandeln . Sie müssen die importierte API verwenden, damit die verfeinerte Swift-Version funktioniert. Daher verwenden sie die __, um sie verfügbar zu halten und sie vor den meisten Tools und Dokumentationen zu verbergen.

Rickster
quelle
@rickster, Welche Bedeutung hat der Unterstrich zu Beginn einer Methode wie dieser?
dev gr
@devgr: Völlig unabhängig, daher würde ich empfehlen, eine separate Frage zu stellen.
Rickster
Klar, ich werde eine separate Frage stellen.
dev gr
Vielen Dank für "nichts zuweisen" für eine Funktionsrückgabe. Das war es, wonach ich gesucht habe.
Absin
8

Neben der akzeptierten Antwort besteht einer der Anwendungsfälle _darin, dass Sie eine lange Zahl in den Code schreiben müssen

Mehr lesbare Nummer

Dies ist für Menschen nicht leicht lesbar:

let x = 1000000000000

Sie können _die Nummer hinzufügen , um sie besser lesbar zu machen:

let x = 1_000_000_000_000
Mojtaba Hosseini
quelle
6

Seit Swift 3 ist die Angabe von Parameternamen bei Funktionsaufrufen obligatorisch - auch für den ersten. Da dies zu großen Problemen beim in Swift 2 geschriebenen Code führen kann, können Sie bei der Deklaration einen Unterstrich verwenden, um zu verhindern, dass der Parametername beim Aufruf geschrieben werden muss. In diesem Fall heißt es also "Der Name des externen Parameters ist mir egal". Wo der externe Parametername ist, nennen Sie die Parameter außerhalb der Funktion (auf Abruf) nicht innerhalb. Diese externen Parameternamen werden als Argumentbezeichnungen bezeichnet. http://ericasadun.com/2016/02/09/the-trouble-with-argument-labels-some- Thoughts/ ... sehen Sie, wie der Parameter zwei Namen erhält? Nun, der erste ist, wohin der Unterstrich geht. Ich hoffe, das hilft und frage, ob ich immer noch verwirrt bin.

Caspar Wylie
quelle
4
func divmod(_ a: Int, _ b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

func divmod(a: Int, b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

Das _ist ein Platzhalter für den Parameternamen. In Ihrem Beispiel rufen Sie sie anders auf, in der zweiten Funktion müssen Sie den Parameternamen schreiben a: 1.

Die Funktionsnamenkonvention von Swift lautet funcName(param1:param2:)und benötigt die _als Platzhalter, um den Namen der Funktion zu erstellen.

Im Vornamen ist der Name

divmod(_:_:)

Während der zweite ist

divmod(a:b:)
Davidhu
quelle