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


120

Được rồi, tôi chỉ cập nhật Xcode lên 7.3 và bây giờ tôi nhận được cảnh báo này:

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

Cách sửa lỗi này khi tôi cần sử dụng var trong hàm này:

public func getQuestionList(var language: String) -> NSArray {
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

6
Thế cònpublic func getQuestionList(inout language: String) -> NSArray
TotoroTotoro

2
Không, đây không phải là sự thay thế phù hợp. OP có lẽ không muốn getQuestioncó bất kỳ tác dụng phụ nào.
BallpointBen

5
Tôi thực sự không biết tại sao họ thậm chí sẽ xem xét loại bỏ điều này. Đó là một trong những tính năng làm cho nhanh chóng trở nên tuyệt vời!
Danny Bravo

Chưa bao giờ sử dụng nó bản thân mình và không hiểu phiền phức.
Mike Taverne

@MikeTaverne (cuối bài trả lời) Hãy xem xét các chức năng sau: func foo(_ bar: int) { /*use bar*/ bar+=1; foo(bar); }. Điều này là không thể nếu không có var params. Bạn cần tạo một var riêng trong hàm và sao chép giá trị hoặc đánh dấu tham số là inout. Cái trước là chậm, cái sau gây ra hành vi không xác định. Nhiều thuật toán sử dụng đệ quy như thế này.
kevin

Câu trả lời:


82

Bạn đã cố gắng gán cho một var mới chưa

public func getQuestionList(language: String) -> NSArray {
    var lang = language
    if self.data.count > 0 {
        if (lang.isEmpty) {
            lang = "NL"
        }
        return self.data.objectForKey("questionList" + lang) as! NSArray
    }

    return NSArray()
}

11
Không thực sự những gì tôi nghĩ OP muốn
diêm sinh

6
Tôi sẽ hiểu câu hỏi của OP giống như @garana. OP không sử dụng inout trong câu hỏi của họ, họ chỉ thay đổi cục bộ một biến có sẵn từ trước .
Eric Aya

11
Trên thực tế đây là giải pháp chính xác. Hãy xem sự tiến hóa vấn đề Swift rằng đề xuất thay đổi này: github.com/apple/swift-evolution/blob/master/proposals/...
Scott Thompson

8
@TimVermeulen Mọi người đều muốn sử dụng một ngôn ngữ tiến bộ. Apple có thể phát triển ngôn ngữ của họ bằng nhiều cách mà không phải bằng cách thay đổi cú pháp mỗi tháng. Như bạn đã biết, rất nhiều tài liệu và đoạn mã trực tuyến đã hết hạn sử dụng hoặc lỗi thời vì Apple. Các nhà phát triển phải đến trang web này để yêu cầu trợ giúp với nhiều câu hỏi ngớ ngẩn liên tục vì nó. Cú pháp phải chắc chắn ngay từ đầu nếu Apple muốn nhiều nhà phát triển giỏi nó.
TomSawyer,

25
Sử dụng var language = language, nếu bạn không muốn giới thiệu một tên biến khác (đó là lợi thế chính của tham số var ngay từ đầu imo)
Harris

102

Cuộc thảo luận về việc loại bỏ Var khỏi một tham số hàm được ghi lại đầy đủ trong bài gửi này trên GitHub: Remove Var Parameters

Trong tài liệu đó, bạn sẽ thấy rằng mọi người thường nhầm lẫn giữa vartham số với inouttham số. Một varsố chỉ đơn giản có nghĩa là tham số là có thể thay đổi trong bối cảnh của các chức năng, trong khi với một inouttham số giá trị của tham số tại điểm lợi nhuận sẽ được sao chép ra khỏi chức năng và vào bối cảnh của người gọi.

Cách chính xác để giải quyết vấn đề này là xóa varkhỏi tham số và đưa vào một varbiến cục bộ. Ở đầu quy trình, hãy sao chép giá trị của tham số vào biến đó.


44
Tôi không hiểu sự thay đổi này, tại sao phải viết một dòng khác để tạo một var cục bộ có thể thay đổi được tốt hơn là chỉ định nghĩa param dưới dạng var?
Ross Barbish

Đối với tôi sự thay đổi này là tốt bởi vì nó được chọn lên các tình huống mà tôi nên đã thực hiện một biến địa phương nhưng tôi đã không phải vì tôi mất một cách dễ dàng ra ngoài và được chấp nhận (cũ) của Swift gợi ý làm đầu vào tham số một var
Dawid

1
Tôi với @RossBarbish về điều này. Vì vậy, ... điều này đang bị loại bỏ vì các nhà phát triển lười biếng không thể phân biệt giữa các tham số inout và var? Pfff ...
Danny Bravo

1
Điều này có vẻ vô cùng không cần thiết ..., họ nên giữ cả hai lựa chọn.
Oscar Gomez

1
Có lẽ swift đã khai báo một biến cục bộ nằm trên tham số đằng sau hậu trường. Bây giờ chúng ta phải làm điều đó bằng tay. Không thay đổi về hiệu suất, nhưng chúng tôi đã đánh mất sự tiện lợi để giúp người mới bắt đầu có một khái niệm đơn giản.
mogelbuster

62

Chỉ cần thêm một dòng này vào đầu hàm:

var language = language

và phần còn lại của mã của bạn có thể không thay đổi, như sau:

public func getQuestionList(language: String) -> NSArray {
    var language = language
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

5
Câu trả lời tốt nhất cho đến nay. Chỉ yêu cầu thay đổi một dòng.
BallpointBen

Nhưng trông không tự nhiên quá
@James

1
Tôi cảm thấy đây là câu trả lời tốt nhất vì nó vẫn giữ nguyên tên. Tương tự như cách các ngôn ngữ thông thường khác thực hiện điều đó.
eonist

1
@RiverSatya Tại sao không chỉ sử dụng tham số trực tiếp?
Declan McKenna,

1
Thực sự là một gợi ý tuyệt vời. Chúng tôi sẽ triển khai nó theo cách này trong Swiftify :)
Crulex

13

Rất nhiều người đang đề xuất một inouttham số, nhưng đó thực sự không phải là những gì họ được thiết kế. Bên cạnh đó, nó không cho phép gọi hàm với một lethằng số hoặc với một chuỗi ký tự. Tại sao bạn không chỉ cần thêm giá trị mặc định vào chữ ký hàm?

public func getQuestionList(language language: String = "NL") -> NSArray {
    if data.count > 0 {
        return data.objectForKey("questionList" + language) as! NSArray
    } else {
        return NSArray()
    }
}

Chỉ cần đảm bảo không gọi getQuestionListbằng chuỗi trống trong trường hợp bạn muốn ngôn ngữ mặc định, nhưng chỉ cần bỏ tham số:

let list = getQuestionList() // uses the default "NL" language

3
Tôi cũng không hiểu tại sao mọi người lại nhảy vào giải pháp inout khi OP thậm chí còn không sử dụng nó ngay từ đầu ...
Eric Aya

1
Họ đã giả định rằng var và inout đã làm điều tương tự.
ryantxr

2

Swift 4

public func getQuestionList(language: inout String) -> NSArray {
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

getQuestionList(language: &someString)

Trong một số trường hợp, như tôi đã trải qua (với các thiết lập phức tạp hơn liên quan đến mảng), việc tạo một thuộc tính mới trong phương thức và thay đổi thuộc tính đó có thể không phải lúc nào cũng hoạt động. Chưa kể, bạn đang làm lộn xộn phương thức thay vì chỉ thêm inoutvào một tham số và &đối số của nó, đó là cú pháp này được tạo ra để làm gì.



0

Tôi nghĩ câu trả lời @Harris và @garanda là cách tiếp cận tốt nhất.

Dù sao trong trường hợp của bạn, không cần var, bạn có thể làm:

public func getQuestionList(language: String) -> NSArray {
    if self.data.count > 0 {
        return self.data.objectForKey("questionList" + (language.isEmpty ? "NL" : language)) as! NSArray
    }
    return NSArray()
}

0

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html

Tham số In-Out

Tham số hàm là hằng số theo mặc định. Việc cố gắng thay đổi giá trị của một tham số hàm từ bên trong phần thân của hàm đó dẫn đến lỗi thời gian biên dịch. Điều này có nghĩa là bạn không thể thay đổi giá trị của một tham số do nhầm lẫn. Nếu bạn muốn một hàm sửa đổi giá trị của một tham số và bạn muốn những thay đổi đó vẫn tồn tại sau khi cuộc gọi hàm kết thúc, hãy xác định tham số đó là một tham số in-out.

Bạn viết một tham số in-out bằng cách đặt từ khóa inout ngay trước loại tham số. Tham số in-out có giá trị được truyền vào hàm, được hàm sửa đổi và được chuyển ngược lại khỏi hàm để thay thế giá trị ban đầu. Để có một cuộc thảo luận chi tiết về hoạt động của các tham số in-out và tối ưu hóa trình biên dịch liên quan, hãy xem In-Out Parameters.

Bạn chỉ có thể chuyển một biến làm đối số cho một tham số in-out. Bạn không thể chuyển một hằng số hoặc một giá trị chữ làm đối số, vì không thể sửa đổi các hằng số và chữ. Bạn đặt dấu và (&) ngay trước tên của một biến khi bạn chuyển nó làm đối số cho một tham số vào ra, để cho biết rằng hàm có thể sửa đổi nó.

GHI CHÚ

Các thông số đầu vào không được có giá trị mặc định và không thể đánh dấu các thông số đa dạng là không tham gia.

Đây là một ví dụ về một hàm được gọi là swapTwoInts ( : :), có hai tham số số nguyên đầu vào được gọi là a và b:

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

Hàm swapTwoInts ( : :) chỉ đơn giản là hoán đổi giá trị của b thành a và giá trị của a thành b. Hàm thực hiện hoán đổi này bằng cách lưu trữ giá trị của a trong một hằng số tạm thời được gọi là tạm thờiA, gán giá trị của b cho a, sau đó gán tạm thờiA cho b.

Bạn có thể gọi hàm swapTwoInts ( : :) với hai biến kiểu Int để hoán đổi giá trị của chúng. Lưu ý rằng tên của someInt và anotherInt được bắt đầu bằng dấu và khi chúng được chuyển đến hàm swapTwoInts ( : :):

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"

Ví dụ trên cho thấy rằng các giá trị ban đầu của someInt và anotherInt được sửa đổi bởi hàm swapTwoInts ( : :), mặc dù ban đầu chúng được định nghĩa bên ngoài hàm.

GHI CHÚ

Tham số vào không giống như trả về giá trị từ một hàm. Ví dụ swapTwoInts ở trên không xác định kiểu trả về hoặc trả về một giá trị, nhưng nó vẫn sửa đổi giá trị của someInt và anotherInt. Tham số in-out là một cách thay thế để một hàm có tác động bên ngoài phạm vi của thân hàm của nó.


0

Đây là một ý tưởng khác. Trường hợp sử dụng của tôi là truyền xung quanh một mảng chuỗi để nối vào nó, mảng này phải được truyền theo phương thức thay đổi. Tôi cũng không muốn có trạng thái trong lớp của mình vì điều này. Vì vậy, tôi đã tạo một lớp chứa mảng và vượt qua nó. Tùy thuộc vào trường hợp sử dụng của bạn, có vẻ ngớ ngẩn khi có một lớp chỉ chứa một biến đó.

private class StringBuilder {
    var buffer: [String] = []

    func append(_ str: String) {
        buffer.append(str)
    }

    func toString() -> String {
        return buffer.joined()
    }
}

Tôi chỉ sử dụng appendjoinedcác phương thức trên mảng để có thể dễ dàng thay đổi kiểu với những thay đổi khác tối thiểu đối với mã của tôi.

Một số ví dụ sử dụng:

private func writeMap(map: LevelMap, url: URL) -> Bool {
    let buffer = StringBuilder()

    if !writeHeader(map: map, buffer: buffer) {
        return false
    }
    if !writeFloors(map: map, buffer: buffer) {
        return false
    }

    let content = buffer.toString()
    do {
        try content.write(to: url, atomically: true, encoding: .utf8)
        return true
    } catch {}
    return false
}

private func writeHeader(map: LevelMap, buffer: StringBuilder) -> Bool {
    buffer.append("something here ...\n")
    return true
}

Câu trả lời của tôi là nếu bạn MUỐN giá trị ban đầu mà người gọi nhìn thấy được sửa đổi. Nếu bạn chỉ muốn có thể gán lại cục bộ giá trị nhưng không ảnh hưởng đến người gọi, các câu trả lời khác ở trên giải quyết điều đó.
webjprgm
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.