Swift torna o parâmetro do método mutável?


123

Como posso lidar com esse erro sem criar variável adicional?

func reduceToZero(x:Int) -> Int {
    while (x != 0) {
        x = x-1            // ERROR: cannot assign to 'let' value 'x'
    }
    return x
}

Não quero criar variável adicional apenas para armazenar o valor de x. É possível fazer o que eu quero?


3
Veja as respostas atualizadas abaixo, o Swift 3 substituiu sua resposta aceita.
— Achi

Respostas:


191

Conforme declarado em outras respostas, a partir do Swift 3, coloque var antes que uma variável tenha sido descontinuada. Embora não seja indicado em outras respostas, é a capacidade de declarar um inoutparâmetro. Pense: passando um ponteiro.

func reduceToZero(_ x: inout Int) {
    while (x != 0) {
        x = x-1     
    }
}

var a = 3
reduceToZero(&a)
print(a) // will print '0'

Isso pode ser particularmente útil na recursão.

As inoutdiretrizes de declaração da Apple podem ser encontradas aqui .


2
Muito obrigado!!!! Estou preso aqui em uma pergunta de recursão. Você salvou minha vida.
— 19416 JW.ZG

2
Deve-se usar isso com cautela, pois isso modifica variáveis ​​fora do escopo da função. Idealmente, você deseja retornar explicitamente o valor alterado dentro da função.
— Chris Gunawardena

2
inoutA palavra-chave deve ser colocada entre o nome e o tipo de parâmetro da seguinte forma: func reduceToZero(x: inout Int) na versão atual do Swift 3.
— Agustí Sánchez

Exceto que isso não parece funcionar para fechamentos, pois os fechamentos capturam apenas os parâmetros inout por valor (pelo menos essa é a mensagem de erro que o Xcode me fornece). Eu uso a solução @GeRyCh neste caso.
— wcochran

Obrigado. Isso funcionou por enquanto, mas é como usar ponteiros em C. Isso sobreviveria a outra versão Swift?
— Krishna Vedula

45

Os parâmetros 'var' foram descontinuados e serão removidos no Swift 3. Portanto, a atribuição de um novo parâmetro parece a melhor maneira agora:

func reduceToZero(x:Int) -> Int {
    var x = x
    while (x != 0) {
        x = x-1            
    }
    return x
}

como mencionado aqui: os parâmetros 'var' foram descontinuados e serão removidos no Swift 3


1
Nesse caso, ele realmente copia o xno novo var x? Ou a Swift está fazendo algo mais eficiente que isso?
— Genki

3
Isso funciona e é o que eu faço, mas parece muito estranho.
— Wcochran

1
@ Gomfucius Nenhuma palavra sobre isso no guia Swift 3.1. Nesse caso ( xcabe no registro), praticamente não há custo. Se xfor uma matriz, estrutura ou objeto que foi alterado, uma cópia quase certamente precisa ser executada (a menos que o otimizador possa analisá-la em linha e alias).
— Wcochran

1
@wcochran Este é um truque legal, mas realmente não há nada de especial acontecendo. Simplesmente eclipsa um parâmetro de entrada com uma cópia var local. Na situação do OP, é melhor substituir os varargumentos do que usar os inoutque podem ter efeitos colaterais indesejados, esp. se o var fosse um ponteiro.
— Echelon

45

Para Swift 1 e 2 (para Swift 3, consulte a resposta de achi usando um parâmetro inout): O argumento de uma função no Swift é letpor padrão; portanto, altere para varse você precisar alterar o valor, por exemplo,

func reduceToZero(var x:Int) -> Int {
    while (x != 0) {
        x = x-1     
    }
    return x
}

2
Por que essa resposta foi votada como o inferno? A outra resposta foi colocada antes desta e contém mais informações que esta.
— Cristik

16
/! \ O uso de var criará uma cópia da variável transmitida nos parâmetros. Portanto, modificá-lo não modificará o valor original. Também varnos parâmetros é muito provável que desapareça nas versões mais recentes do Swift por github.com/apple/swift-evolution/blob/master/proposals/…
— Matthieu Riegler

17
var palavra-chave no paremeter método será depreciado em Swift 3.
— Boon

4
Eu acho que com o Swift 3, não poderemos mais fazer isso. Teremos que criar uma cópia variável da matriz e retornar essa matriz modificada.
— C0D3 18/05

Esta resposta é a resposta correta: stackoverflow.com/questions/24077880/...
— Achi

14

Resposta Swift3 para passar o ponteiro do array mutável.

Função:

func foo(array: inout Array<Int>) {
    array.append(1)
}

Chamada para funcionar:

var a = Array<Int>()
foo(array:&a)

Honestamente, não tenho certeza se isso está correto, pois o terreno do Swift está sempre mudando. Eu pensei isso melhor do que fazer var array = array dentro da função, porque isso faz uma cópia (e na verdade não afeta a estrutura original da matriz)? É uma abordagem de design melhor à abordagem var mencionada acima e depois retorna a nova matriz mutada?
— joshd

7

No Swift, você apenas adiciona a varpalavra - chave antes do nome da variável na declaração da função:

func reduceToZero(var x:Int) -> Int { // notice the "var" keyword
    while (x != 0) {
        x = x-1            
    }
    return x
}

Consulte a subseção "Parâmetros constantes e variáveis" no capítulo "Funções" do livro Swift (página 210 do iBook como é hoje).


7
Os parâmetros 'var' foram descontinuados e serão removidos no Swift 3
— Regis St-Gelais

1
Não é válido para o Swift 4 e mais recente.
— ilkayaktas

0

Existem alguns casos em que não precisamos usar inout

Podemos usar algo assim se você quiser que as alterações / escopo sejam apenas dentro da função:

func manipulateData(a: Int) -> Int {
    var a = a
    // ...
}

0

Solução usando Swift5 com programação funcional ...

func reduceToZeroFP(x:Int) -> Int {
    x == 0 ? x : reduceToZeroFP(x: x - 1)
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.