¿Por qué necesito guiones bajos en Swift?

161

Aquí dice: "Nota: _significa" no me importa ese valor "", pero viniendo de JavaScript, no entiendo lo que eso significa.

La única forma en que puedo imprimir estas funciones es usando los guiones bajos antes de los parámetros:

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))

Sin los guiones bajos, tengo que escribirlo así para evitar errores:

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))

No entiendo este uso de subrayado. ¿Cuándo, cómo y por qué uso estos guiones bajos?

Michael Rader
fuente

Respuestas:

354

Hay algunos matices para diferentes casos de uso, pero generalmente un guión bajo significa "ignorar esto".


Al declarar una nueva función, un guión bajo le dice a Swift que el parámetro no debe tener etiqueta cuando se lo llama, ese es el caso que está viendo. Una declaración de función más completa se ve así:

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

"etiqueta" es una etiqueta de argumento y debe estar presente cuando se llama a la función. (Y desde Swift 3, se requieren etiquetas para todos los argumentos de forma predeterminada). "Nombre" es el nombre de la variable para ese argumento que utiliza dentro de la función. Una forma más corta se ve así:

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

Este es un acceso directo que le permite usar la misma palabra para la etiqueta del argumento externo y el nombre del parámetro interno. Es equivalente a func myFunc(name name: Int).

Si desea que su función sea invocable sin etiquetas de parámetros, use el guión bajo _para que la etiqueta sea nada / ignorada. (En ese caso, debe proporcionar un nombre interno si desea poder utilizar el parámetro).

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

En una declaración de asignación, un guión bajo significa "no asignar a nada". Puede usar esto si desea llamar a una función que devuelve un resultado pero no le importa el valor devuelto.

_ = someFunction()

O, como en el artículo al que se vinculó, ignorar un elemento de una tupla devuelta:

let (x, _) = someFunctionThatReturnsXandY()

Cuando escribe un cierre que implementa algún tipo de función definida, puede usar el guión bajo para ignorar ciertos parámetros.

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

Del mismo modo, al declarar una función que adopta un protocolo o anula un método de superclase, puede usar los nombres de los_ parámetros para ignorarlos. Dado que el protocolo / superclase también podría definir que el parámetro no tiene etiqueta, incluso puede terminar con dos guiones bajos seguidos.

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
    }
}

Algo relacionado con los dos últimos estilos: cuando se usa una construcción de control de flujo que une una variable / constante local, puede usar _para ignorarla. Por ejemplo, si desea iterar una secuencia sin necesidad de acceder a sus miembros:

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

Si está vinculando casos de tupla en una declaración de cambio, el guión bajo puede funcionar como un comodín, como en este ejemplo (acortado de uno en El lenguaje de programación rápido ):

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")
}

Una última cosa que no está muy relacionado, pero que voy a incluir ya que (según lo observado por los comentarios) que parece conducir a la gente aquí: Un guión en un identificador - por ejemplo var _foo, func do_the_thing(), struct Stuff_- medios nada en particular a Swift, pero tiene algunos usos entre programadores.

Los guiones bajos dentro de un nombre son una opción de estilo, pero no se prefieren en la comunidad Swift, que tiene convenciones fuertes sobre el uso de UpperCamelCase para los tipos y lowerCamelCase para todos los demás símbolos.

Prefijar o sufijar un nombre de símbolo con guión bajo es una convención de estilo, históricamente utilizada para distinguir símbolos privados / de uso interno de la API exportada. Sin embargo, Swift tiene modificadores de acceso para eso, por lo que esta convención generalmente se considera no idiomática en Swift.

Algunos símbolos con prefijos de doble subrayado ( func __foo()) acechan en las profundidades de los SDK de Apple: estos son símbolos (Obj) C importados a Swift usando el NS_REFINED_FOR_SWIFTatributo. Apple usa eso cuando quieren hacer una versión "más ágil" de una API (Obj) C, por ejemplo, para convertir un método independiente del tipo en un método genérico . Necesitan usar la API importada para hacer que la versión refinada de Swift funcione, por lo que la usan __para mantenerla disponible mientras la ocultan de la mayoría de las herramientas y la documentación.

rickster
fuente
@rickster, ¿Cuál es el significado del guión bajo al inicio de un método, como este?
dev gr
@devgr: Completamente no relacionado, por lo que recomendaría publicar una pregunta por separado.
rickster
Claro, publicaré una pregunta por separado.
dev gr
Gracias por "no asignar nada" por un retorno de función. Esto era lo que estaba buscando.
absin
8

Además de la respuesta aceptada, uno de los casos de uso _es cuando necesita escribir un número largo en el código

Número más legible

Esto no es fácil de leer por humanos:

let x = 1000000000000

Puede agregar _el número para que sea más legible para los humanos:

let x = 1_000_000_000_000
Mojtaba Hosseini
fuente
6

Desde Swift 3, la especificación de los nombres de los parámetros en las llamadas a funciones se ha convertido en obligatorio, incluso para el primero. Entonces, debido a que eso podría causar un gran problema al código escrito en swift 2, puede usar un guión bajo en la declaración para evitar tener que escribir el nombre del parámetro en la llamada. Entonces, en este caso, está diciendo "no me importa el nombre del parámetro externo". Donde el nombre del parámetro externo es lo que llama los parámetros fuera de la función (en llamada) no dentro. Estos nombres de parámetros externos se denominan etiquetas de argumento. http://ericasadun.com/2016/02/09/the-trouble-with-argument-labels-some-thoughts/ ... ¿ve cómo se le dan dos nombres al parámetro? bueno, el primero es hacia dónde va el guión bajo. Espero que esto ayude, y pregunte si aún está confundido.

Caspar Wylie
fuente
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)
}

El _es un marcador de posición para el nombre del parámetro. En su ejemplo, los llama de manera diferente, en la segunda función, necesita escribir el nombre del parámetro a: 1.

La convención de nombre de función de Swift es funcName(param1:param2:), y necesita _como marcador de posición para crear el nombre de la función.

En el primer nombre, el nombre es

divmod(_:_:)

Mientras que el segundo es

divmod(a:b:)
davidhu
fuente