Swift make tham số phương thức có thể thay đổi?


123

Làm cách nào để xử lý lỗi này mà không cần tạo thêm biến?

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

Tôi không muốn tạo thêm biến chỉ để lưu giá trị của x. Thậm chí có thể làm những gì tôi muốn?


3
Xem các câu trả lời được cập nhật bên dưới, Swift 3 đã không chấp nhận câu trả lời được chấp nhận của bạn.
achi

Câu trả lời:


192

Như đã nêu trong các câu trả lời khác, kể từ Swift 3, việc đặt var trước một biến không còn được dùng nữa. Mặc dù không được nêu trong các câu trả lời khác là khả năng khai báo một inouttham số. Hãy suy nghĩ: đi qua một con trỏ.

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

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

Điều này có thể đặc biệt hữu ích trong đệ quy.

inoutHướng dẫn khai báo của Apple có thể được tìm thấy tại đây .


2
Cảm ơn rât nhiều!!!! Tôi bị mắc kẹt ở đây về một câu hỏi đệ quy. Bạn đã cứu cuộc đời tôi.
JW.ZG

2
Nên sử dụng điều này một cách thận trọng vì điều này sửa đổi các biến bên ngoài phạm vi hàm. Lý tưởng nhất là bạn muốn trả về giá trị bạn đã thay đổi bên trong hàm một cách rõ ràng.
Chris Gunawardena

2
inouttừ khóa nên được đặt giữa tên tham số và kiểu tham số như sau: func reduceToZero(x: inout Int) trong phiên bản Swift 3 hiện tại.
Agustí Sánchez

Ngoại trừ điều này dường như không hoạt động đối với các bao đóng vì các đóng rõ ràng chỉ nắm bắt các tham số inout theo giá trị (ít nhất đó là thông báo lỗi mà Xcode cung cấp cho tôi). Tôi sử dụng giải pháp @GeRyCh trong trường hợp này.
wcochran

Cảm ơn bạn. Điều này đã hoạt động ngay bây giờ, nhưng nó giống như sử dụng con trỏ trong C. Điều này sẽ tồn tại một phiên bản Swift khác?
Krishna Vedula,

45

Tham số 'var' không được dùng nữa và sẽ bị xóa trong Swift 3. Vì vậy, gán cho một tham số mới có vẻ là cách tốt nhất hiện nay:

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

như đã đề cập ở đây: Tham số 'var' không được dùng nữa và sẽ bị xóa trong Swift 3


1
Trong trường hợp này, nó có thực sự sao chép xcái mới var xkhông? Hay Swift đang làm điều gì đó hiệu quả hơn thế?
Genki

3
Điều này hiệu quả và là những gì tôi làm, nhưng nó có vẻ rất khó xử.
wcochran

1
@Gomfucius Không có một lời nào về điều này trong hướng dẫn Swift 3.1. Trong trường hợp này ( xphù hợp với đăng ký) hầu như không có chi phí. Nếu xlà mảng, cấu trúc hoặc đối tượng bị thay đổi, thì một bản sao gần như chắc chắn cần được thực hiện (trừ khi trình tối ưu hóa có thể phân tích nội tuyến và đặt bí danh cho nó).
wcochran

1
@wcochran Đây là một mẹo nhỏ, nhưng thực sự không có gì đặc biệt xảy ra. Nó chỉ đơn giản là làm lu mờ một tham số đầu vào bằng một bản sao var cục bộ. Trong tình hình của OP, nó là một sự thay thế tốt hơn cho varargs hơn là sử dụng inoutcó thể có tác dụng phụ ngoài ý muốn, đặc biệt. nếu var là một con trỏ.
Echelon

45

Đối với Swift 1 và 2 (đối với Swift 3, hãy xem câu trả lời của achi sử dụng tham số inout): Đối số của một hàm trong Swift là lettheo mặc định, vì vậy hãy thay đổi nó thành varnếu bạn cần thay đổi giá trị, tức là,

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

2
Tại sao câu trả lời này lại được bình chọn nhiều như vậy? Câu trả lời khác được đặt trước câu trả lời này và chứa nhiều thông tin hơn câu trả lời này.
Cristik

16
/! \ Sử dụng var sẽ tạo một bản sao của biến được truyền vào các tham số. Vì vậy, việc sửa đổi nó sẽ không làm thay đổi giá trị ban đầu. Cũng vartrong thông số là rất có khả năng biến mất trong các phiên bản Swift mới hơn mỗi github.com/apple/swift-evolution/blob/master/proposals/...
Matthieu Riegler

17
Từ khóa var trong method paremeter sẽ không được chấp nhận trong Swift 3.
Boon

4
Tôi nghĩ với Swift 3, chúng tôi sẽ không thể làm điều này nữa. Chúng ta sẽ phải tạo một bản sao biến của mảng và trả về mảng đã sửa đổi đó.
C0D3

Câu trả lời này là câu trả lời đúng: stackoverflow.com/questions/24077880/...
Achi

14

Câu trả lời Swift3 để truyền con trỏ mảng có thể thay đổi.

Chức năng:

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

Gọi đến chức năng:

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

Thành thật mà nói, tôi không chắc liệu điều này có chính xác hay không vì nền tảng Swift luôn thay đổi. Tôi nghĩ điều này tốt hơn là thực hiện var array = array bên trong hàm vì điều đó tạo ra một bản sao (và thực sự không ảnh hưởng đến cấu trúc mảng ban đầu)? Có phải cách tiếp cận thiết kế tốt hơn cho cách tiếp cận var đã nói ở trên và sau đó trả về mảng mới bị đột biến không?
joshd

7

Trong Swift, bạn chỉ cần thêm vartừ khóa vào trước tên biến trong khai báo hàm:

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

Tham khảo tiểu mục "Tham số hằng và biến" trong chương "Hàm" của sách Swift (trang 210 của iBook như ngày nay).


7
Tham số 'var' không được dùng nữa và sẽ bị xóa trong Swift 3
Regis St-Gelais vào

1
Không hợp lệ cho Swift 4 và mới hơn.
ilkayaktas

0

Có một số trường hợp chúng tôi không muốn sử dụng inout

Chúng ta có thể sử dụng một cái gì đó như thế này nếu bạn muốn các thay đổi / phạm vi chỉ nằm bên trong hàm:

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

0

Giải pháp sử dụng Swift5 với Lập trình chức năng ...

func reduceToZeroFP(x:Int) -> Int {
    x == 0 ? x : reduceToZeroFP(x: x - 1)
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.