Cepat membuat parameter metode bisa berubah?

123

Bagaimana cara mengatasi kesalahan ini tanpa membuat variabel tambahan?

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

Saya tidak ingin membuat variabel tambahan hanya untuk menyimpan nilai x. Apakah mungkin untuk melakukan apa yang saya inginkan?

Gabriel
sumber
3
Lihat jawaban yang diperbarui di bawah ini, Swift 3 telah menghentikan jawaban yang Anda terima.
achi

Jawaban:

192

Seperti yang dinyatakan dalam jawaban lain, mulai dari Swift 3 menempatkan var sebelum variabel tidak digunakan lagi. Meskipun tidak dinyatakan dalam jawaban lain adalah kemampuan untuk mendeklarasikan suatu inoutparameter. Pikirkan: memberikan sebuah pointer.

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

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

Ini bisa sangat berguna dalam rekursi.

inoutPanduan deklarasi Apple dapat ditemukan di sini .

achi
sumber
2
Terima kasih banyak!!!! Saya terjebak di sini pada pertanyaan rekursi. Anda menyelamatkan hidup saya.
JW.ZG
2
Harus menggunakan ini dengan hati-hati karena ini mengubah variabel di luar ruang lingkup fungsi. Idealnya Anda ingin secara eksplisit mengembalikan nilai yang Anda ubah di dalam fungsi.
Chris Gunawardena
2
inoutkata kunci harus ditempatkan di antara nama parameter dan jenis parameter seperti ini: func reduceToZero(x: inout Int) di versi Swift 3 saat ini.
Agustí Sánchez
Kecuali ini tampaknya tidak berfungsi untuk penutupan karena closures jelas hanya menangkap parameter inout berdasarkan nilai (setidaknya itu adalah pesan kesalahan yang diberikan Xcode kepada saya). Saya menggunakan solusi @GeRyCh dalam kasus ini.
wcochran
Terima kasih. Ini berfungsi untuk saat ini, tetapi seperti menggunakan pointer di C. Apakah ini akan bertahan dalam versi Swift lain?
Krishna Vedula
45

Parameter 'var' tidak digunakan lagi dan akan dihapus di Swift 3. Jadi menetapkan ke parameter baru sepertinya cara terbaik sekarang:

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

seperti yang disebutkan di sini: Parameter 'var' tidak digunakan lagi dan akan dihapus di Swift 3

GeRyCh
sumber
1
Dalam hal ini, apakah itu benar-benar menyalin xdi yang baru var x? Atau apakah Swift melakukan sesuatu yang lebih efisien dari itu?
Genki
3
Ini berhasil dan itulah yang saya lakukan, tetapi tampaknya sangat canggung.
wcochran
1
@Gomfucius Tidak sepatah kata pun tentang ini di panduan Swift 3.1. Dalam hal ini ( xcocok di daftarkan) hampir tidak ada biaya. Jika xadalah array, struct, atau objek yang dimutasi, maka salinan hampir pasti perlu dilakukan (kecuali pengoptimal dapat menganalisisnya secara inline dan alias).
wcochran
1
@wcochran Ini adalah trik yang bagus, tapi sebenarnya tidak ada yang istimewa yang terjadi. Ini hanya menutupi parameter input dengan salinan var lokal. Dalam situasi OP itu adalah pengganti yang lebih baik untuk varargs daripada menggunakan inoutyang mungkin memiliki efek samping yang tidak diinginkan, esp. jika var adalah sebuah pointer.
Eselon
45

Untuk Swift 1 dan 2 (untuk Swift 3 lihat jawaban dengan achi menggunakan parameter masuk): Argumen fungsi di Swift secara letdefault jadi ubah ke varjika Anda perlu mengubah nilainya, yaitu,

func reduceToZero(var x:Int) -> Int {
    while (x != 0) {
        x = x-1     
    }
    return x
}
LML
sumber
2
Mengapa jawaban ini dipilih seperti neraka? Jawaban lain ditempatkan sebelum yang ini, dan berisi lebih banyak informasi daripada yang ini.
Cristik
16
/! \ Menggunakan var akan membuat salinan variabel yang diteruskan dalam parameter. Jadi memodifikasinya tidak akan mengubah nilai aslinya. Juga vardalam parameter sangat mungkin menghilang dalam versi Swift yang lebih baru per github.com/apple/swift-evolution/blob/master/proposals/…
Matthieu Riegler
17
Kata kunci var di paremeter metode tidak akan digunakan lagi di Swift 3.
Boon
4
Saya pikir dengan Swift 3, kami tidak akan dapat melakukan ini lagi. Kita harus membuat salinan variabel dari array dan mengembalikan array yang dimodifikasi itu.
C0D3
Jawaban ini adalah jawaban yang benar: stackoverflow.com/questions/24077880/…
achi
14

Jawaban Swift3 untuk meneruskan pointer array yang bisa berubah.

Fungsi:

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

Panggilan untuk berfungsi:

var a = Array<Int>()
foo(array:&a)
joshd
sumber
Sejujurnya, saya tidak yakin apakah ini benar karena Swift ground selalu berubah. Saya pikir ini lebih baik daripada melakukan var array = array di dalam fungsi karena itu membuat salinan (dan tidak benar-benar mempengaruhi struktur array asli)? Apakah pendekatan desain yang lebih baik untuk pendekatan var yang disebutkan di atas dan kemudian mengembalikan larik bermutasi yang baru?
joshd
7

Di Swift Anda cukup menambahkan varkata kunci sebelum nama variabel di deklarasi fungsi:

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

Lihat sub-bagian "Parameter Konstan dan Variabel" di bab "Fungsi" di buku Swift (halaman 210 iBook seperti sekarang ini).

DK_
sumber
7
Parameter 'var' tidak digunakan lagi dan akan dihapus di Swift 3
Regis St-Gelais
1
Tidak berlaku untuk Swift 4 dan yang lebih baru.
ilkayaktas
0

Ada beberapa kasus di mana kami tidak perlu menggunakannya inout

Kita dapat menggunakan sesuatu seperti ini jika Anda ingin perubahan / cakupan hanya di dalam fungsi:

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

Solusi menggunakan Swift5 dengan Pemrograman Fungsional ...

func reduceToZeroFP(x:Int) -> Int {
    x == 0 ? x : reduceToZeroFP(x: x - 1)
}
Jules Burt
sumber