Por que preciso de sublinhados rapidamente?

161

Aqui diz: "Nota: os _meios" Eu não me importo com esse valor "", mas, vindo do JavaScript, não entendo o que isso significa.

A única maneira de obter essas funções para imprimir era usar os sublinhados antes dos 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))

Sem os sublinhados, tenho que escrevê-lo assim para evitar erros:

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

Não entendo esse uso de sublinhado. Quando, como e por que eu uso esses sublinhados?

Michael Rader
fonte

Respostas:

354

Existem algumas nuances para diferentes casos de uso, mas geralmente um sublinhado significa "ignorar isso".


Ao declarar uma nova função, um sublinhado informa ao Swift que o parâmetro não deve ter rótulo quando chamado - é o caso que você está vendo. Uma declaração de função mais completa se parece com isso:

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

"label" é um rótulo de argumento e deve estar presente quando você chama a função. (E, desde o Swift 3, os rótulos são obrigatórios para todos os argumentos por padrão.) "Name" é o nome da variável para esse argumento que você usa dentro da função. Um formulário mais curto se parece com isso:

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

Este é um atalho que permite usar a mesma palavra para o rótulo de argumento externo e o nome do parâmetro interno. É equivalente a func myFunc(name name: Int).

Se você deseja que sua função possa ser chamada sem rótulos de parâmetro, use o sublinhado _para fazer com que o rótulo seja nada / ignorado. (Nesse caso, você deve fornecer um nome interno se quiser poder usar o parâmetro.)

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

Em uma declaração de atribuição, um sublinhado significa "não atribuir a nada". Você pode usar isso se desejar chamar uma função que retorne um resultado, mas não se importe com o valor retornado.

_ = someFunction()

Ou, como no artigo ao qual você vinculou, ignorar um elemento de uma tupla retornada:

let (x, _) = someFunctionThatReturnsXandY()

Ao escrever um fechamento que implementa algum tipo de função definido, você pode usar o sublinhado para ignorar determinados parâmetros.

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

Da mesma forma, ao declarar uma função que adota um protocolo ou substitui um método de superclasse, você pode usar os nomes de_ parâmetros para ignorá- los . Como o protocolo / superclasse também pode definir que o parâmetro não possui rótulo, você pode até acabar com dois sublinhados 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
    }
}

Um pouco relacionado aos dois últimos estilos: ao usar uma construção de controle de fluxo que liga uma variável / constante local, você pode usá _-la para ignorá-la. Por exemplo, se você deseja iterar uma sequência sem precisar acessar seus membros:

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

Se você estiver vinculando casos de tupla em uma instrução switch, o sublinhado poderá funcionar como um curinga, como neste exemplo (abreviado de um na linguagem de programação Swift ):

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

Uma última coisa que não é bem relacionado, mas que vou incluir desde (como observado por comentários) parece levar as pessoas aqui: Um sublinhado em um identificador - por exemplo var _foo, func do_the_thing(), struct Stuff_- não significa nada em particular a Swift, mas tem alguns usos entre programadores.

Sublinhados em um nome são uma opção de estilo, mas não são preferidos na comunidade Swift, que possui fortes convenções sobre o uso de UpperCamelCase para tipos e lowerCamelCase para todos os outros símbolos.

A prefixação ou o sufixo de um nome de símbolo com sublinhado é uma convenção de estilo, usada historicamente para distinguir símbolos particulares / somente para uso interno da API exportada. No entanto, o Swift possui modificadores de acesso para isso, portanto essa convenção geralmente é vista como não idiomática no Swift.

Alguns símbolos com prefixos de sublinhado duplo ( func __foo()) estão nas profundezas dos SDKs da Apple: Estes são símbolos (Obj) C importados para o Swift usando o NS_REFINED_FOR_SWIFTatributo A Apple usa isso quando deseja criar uma versão "mais Swifty" de uma API (Obj) C - por exemplo, para transformar um método independente de tipo em um método genérico . Eles precisam usar a API importada para fazer com que a versão refinada do Swift funcione; portanto, eles usam isso __para mantê-la disponível enquanto ocultam a maioria das ferramentas e documentação.

rickster
fonte
@ Rickster, Qual é o significado de sublinhado no início de um método, como este-> func _copyContents (inicializando ptr: UnsafeMutableBufferPointer <Element>) -> (Iterator, UnsafeMutableBufferPointer <Element> .Index)} do protocolo Sequence.
dev gr
@devgr: completamente sem relação, por isso recomendo postar uma pergunta separada.
Rickster 19/05/19
Claro, vou postar uma pergunta separada.
dev gr
Obrigado por "não atribuir a nada" pelo retorno de uma função. Era isso que eu estava procurando.
absin
8

Além da resposta aceita, um dos casos de uso de _é quando você precisa escrever um número longo no código

Número mais legível

Isso não é fácil de ser lido por humanos:

let x = 1000000000000

Você pode adicionar _o número para torná-lo mais legível por humanos:

let x = 1_000_000_000_000
Mojtaba Hosseini
fonte
6

Desde o Swift 3, a especificação de nomes de parâmetros em chamadas de função tornou-se obrigatória - mesmo para o primeiro. Portanto, como isso pode causar um grande problema ao código escrito em swift 2, você pode usar um sublinhado na declaração para evitar a necessidade de escrever o nome do parâmetro na chamada. Portanto, neste caso, está dizendo "não se importa com o nome do parâmetro externo". Onde o nome do parâmetro externo é o que você chama de parâmetros fora da função (de plantão) e não dentro. Esses nomes de parâmetros externos são chamados de rótulos de argumento. http://ericasadun.com/2016/02/09/the-trouble-with-argument-labels-some-thoughts/ ... vê como o parâmetro recebe dois nomes? bem, o primeiro é para onde o sublinhado está indo. Espero que isso ajude e pergunte se ainda está confuso.

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

O _é um espaço reservado para o nome do parâmetro. No seu exemplo, você os chama de maneira diferente. Na segunda função, você precisa escrever o nome do parâmetro a: 1.

A convenção de nome da função de Swift é funcName(param1:param2:)e ela precisa _como espaço reservado para criar o nome da função.

No primeiro nome, o nome é

divmod(_:_:)

Considerando que o segundo é

divmod(a:b:)
davidhu
fonte