Hızlı yöntem parametresi değiştirilebilir mi?


123

Ek değişken oluşturmadan bu hatayla nasıl başa çıkabilirim?

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

Sadece x'in değerini saklamak için ek değişken oluşturmak istemiyorum. İstediğimi yapmak mümkün mü?


3
Aşağıdaki güncellenmiş cevaplara bakın, Swift 3 kabul ettiğiniz cevabı kullanımdan kaldırdı.
achi

Yanıtlar:


193

Diğer cevaplarda belirtildiği gibi, Swift 3'ten itibaren değişkenlerin önüne var yerleştirilmesi kullanımdan kaldırılmıştır. Diğer cevaplarda belirtilmese de, bir inoutparametre bildirme kabiliyetidir . Düşünün: bir işaretçiyi geçmek.

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

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

Bu, özellikle özyinelemede yararlı olabilir.

Apple'ın inoutbeyan yönergeleri burada bulunabilir .


2
Çok teşekkür ederim!!!! Burada bir özyineleme sorusunda sıkıştım kaldım. Hayatımı kurtardın.
JW.ZG

2
Bu, işlev kapsamı dışındaki değişkenleri değiştirdiği için bunu dikkatli kullanmalısınız. İdeal olarak, değiştirdiğiniz değeri işlevin içinde açıkça döndürmek istersiniz.
Chris Gunawardena

2
inoutanahtar kelime, parametre adı ve parametre türü arasına şu şekilde yerleştirilmelidir: func reduceToZero(x: inout Int) mevcut Swift 3 sürümünde.
Agustí Sánchez

Ancak bu, kapanışlar için işe yaramıyor gibi görünmektedir, çünkü kapamalar açıkça sadece giriş parametrelerini değere göre yakalar (en azından bu, Xcode'un bana verdiği hata mesajıdır). Bu durumda @GeRyCh çözümünü kullanıyorum.
wcochran

Teşekkür ederim. Bu şimdilik işe yaradı, ancak C'deki işaretçileri kullanmak gibi. Bu, başka bir Swift versiyonunda hayatta kalacak mı?
Krishna Vedula

45

'var' parametreleri kullanımdan kaldırıldı ve Swift 3'te kaldırılacak. Bu nedenle yeni bir parametreye atamak şimdi en iyi yol gibi görünüyor:

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

burada belirtildiği gibi: 'var' parametreleri kullanımdan kaldırıldı ve Swift 3'te kaldırılacak


1
Bu durumda, aslında kopya yok xyeni de var x? Yoksa Swift bundan daha verimli bir şey mi yapıyor?
Genki

3
Bu işe yarıyor ve benim yaptığım şey, ama çok garip görünüyor.
wcochran

1
@Gomfucius Swift 3.1 kılavuzunda bununla ilgili tek bir söz yok. Bu durumda ( xsicile sığar) neredeyse hiç maliyet yoktur. Eğer xdizi, yapı veya mutasyona uğrar nesnedir, sonra neredeyse kesinlikle bir kopyası (iyileştirici bunu satır içi analiz ve takma sürece) yapılması gerekmektedir.
wcochran

1
@wcochran Bu güzel bir numara, ama gerçekten özel bir şey yok. Yerel bir değişken kopyasıyla bir girdi parametresini örtmek basitçe. OP'nin durumunda , istenmeyen yan etkilere sahip olabilen, özellikle varargümanlar yerine kullanmaktan daha iyi bir alternatiftir inout. var bir işaretçi olsaydı.
Echelon

45

Swift 1 ve 2 için (Swift 3 için bir inout parametresi kullanarak achi tarafından verilen cevaba bakın): Swift'deki bir işlevin argümanı letvarsayılan olarak, bu nedenle vardeğeri değiştirmeniz gerekirse olarak değiştirin, yani,

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

2
Bu cevap neden cehennem gibi yükseltildi? Diğer cevap bunun öncesine yerleştirildi ve bundan daha fazla bilgi içeriyor.
Cristik

16
/! \ Var kullanmak, parametrelerde geçirilen değişkenin bir kopyasını oluşturur. Bu yüzden onu değiştirmek, orijinal değeri değiştirmez. Ayrıca varparametrelerde, github.com/apple/swift-evolution/blob/master/proposals/…
Matthieu Riegler

17
yöntem parametresindeki var anahtar sözcüğü Swift 3'te kullanımdan kaldırılacak.
Boon

4
Swift 3 ile bunu artık yapamayacağımızı düşünüyorum. Dizinin değişken bir kopyasını oluşturmalı ve değiştirilmiş diziyi döndürmeliyiz.
C0D3

Bu cevap doğru cevaptır: stackoverflow.com/questions/24077880/…
achi

14

Değişken dizi işaretçisi geçmek için Swift3 yanıtı.

İşlev:

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

İşlev çağrısı:

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

Açıkçası, Swift zemini sürekli değiştiği için bunun doğru olup olmadığından emin değilim. Bunun, işlev içinde var array = array yapmaktan daha iyi olduğunu düşündüm çünkü bu bir kopya oluşturur (ve aslında orijinal dizi yapısını etkilemez)? Yukarıda bahsedilen var yaklaşımı için daha iyi bir tasarım yaklaşımı ve ardından yeni mutasyona uğramış diziyi döndürmek mi?
joshd

7

Swift'de var, işlev bildirimindeki değişken adının önüne anahtar kelimeyi eklemeniz yeterlidir:

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

Swift kitabının "İşlevler" bölümündeki "Sabit ve Değişken Parametreler" alt bölümüne bakın (bugün olduğu gibi iBook'un 210. sayfası).


7
'var' parametreleri kullanımdan kaldırıldı ve Swift 3
Regis St-Gelais

1
Swift 4 ve daha yenisi için geçerli değildir.
ilkayaktas

0

Kullanmamamız gereken bazı durumlar var inout

Değişikliklerin / kapsamın yalnızca işlevin içinde olmasını istiyorsanız, buna benzer bir şey kullanabiliriz:

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

0

Fonksiyonel Programlama ile Swift5 kullanarak Çözüm ...

func reduceToZeroFP(x:Int) -> Int {
    x == 0 ? x : reduceToZeroFP(x: x - 1)
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.