เลิกใช้พารามิเตอร์ 'var' และจะถูกลบออกใน Swift 3


120

เอาล่ะฉันเพิ่งอัปเดต Xcode เป็น 7.3 และตอนนี้ฉันได้รับคำเตือนนี้:

เลิกใช้พารามิเตอร์ 'var' และจะถูกลบออกใน Swift 3

วิธีแก้ไขเมื่อฉันต้องการใช้ var ในฟังก์ชันนี้:

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
How aboutpublic func getQuestionList(inout language: String) -> NSArray
TotoroTotoro

2
ไม่นี่ไม่ใช่อุปกรณ์ทดแทนที่เหมาะสม OP อาจไม่ต้องการgetQuestionให้เกิดผลข้างเคียงใด ๆ
BallpointBen

5
ฉันไม่รู้ว่าทำไมพวกเขาถึงคิดจะลบสิ่งนี้ออกไป มันเป็นหนึ่งในคุณสมบัติที่ทำให้รวดเร็วน่ากลัว!
Danny Bravo

ไม่เคยใช้เองและไม่เข้าใจเอะอะ
Mike Taverne

@MikeTaverne (ตอบช้า) พิจารณาฟังก์ชันต่อไปนี้: func foo(_ bar: int) { /*use bar*/ bar+=1; foo(bar); }. สิ่งนี้เป็นไปไม่ได้หากไม่มีพารามิเตอร์ตัวแปร คุณต้องสร้าง var แยกต่างหากภายในฟังก์ชันและคัดลอกค่าหรือทำเครื่องหมายพารามิเตอร์เป็น inout อดีตช้าส่วนหลังทำให้เกิดพฤติกรรมที่ไม่ได้กำหนด อัลกอริทึมจำนวนมากใช้การเรียกซ้ำเช่นนี้
kevin

คำตอบ:


82

คุณพยายามกำหนดให้ตัวแปรใหม่หรือไม่

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
ไม่ใช่สิ่งที่ฉันคิดว่า OP ต้องการจริงๆ
brimstone

6
ฉันคงเข้าใจคำถามของ OP แบบเดียวกับ @garana OP ไม่ได้ใช้ inout ในคำถามของพวกเขาพวกเขาเพียงแค่เปลี่ยนตัวแปรที่มีอยู่แล้วในเครื่อง
Eric Aya

11
จริงๆแล้วนี่เป็นวิธีแก้ปัญหาที่ถูกต้อง โปรดดูปัญหาวิวัฒนาการของ Swift ที่เสนอการเปลี่ยนแปลงนี้: github.com/apple/swift-evolution/blob/master/proposals/…
Scott Thompson

8
@TimVermeulen ทุกคนต้องการใช้ภาษาที่ก้าวหน้า Apple สามารถพัฒนาภาษาของพวกเขาได้หลายวิธีโดยไม่ต้องเปลี่ยนไวยากรณ์ทุก ๆ เดือน อย่างที่ทราบกันดีว่าเอกสารออนไลน์และข้อมูลโค้ดจำนวนมากกำลังจะหมดอายุหรือล้าสมัยเนื่องจาก Apple นักพัฒนาต้องเข้ามาที่ไซต์นี้เพื่อขอความช่วยเหลือเกี่ยวกับคำถามโง่ ๆ หลาย ๆ ครั้งเพราะมัน ไวยากรณ์ต้องมีความมั่นคงตั้งแต่ต้นหาก Apple ต้องการให้นักพัฒนาเก่ง ๆ มากขึ้น
TomSawyer

25
ใช้ var language = ภาษาหากคุณไม่ต้องการแนะนำชื่อตัวแปรอื่น (ซึ่งเป็นข้อได้เปรียบหลักของพารามิเตอร์ var ใน imo อันดับแรก)
Harris

102

การอภิปรายเกี่ยวกับการลบ Var ออกจากพารามิเตอร์ฟังก์ชันได้รับการบันทึกไว้อย่างสมบูรณ์ภายในการส่งนี้ใน GitHub: Remove Var Parameters

ในเอกสารนั้นคุณจะพบว่าผู้คนมักสับสนระหว่างvarพารามิเตอร์กับinoutพารามิเตอร์ varพารามิเตอร์ก็หมายความว่าพารามิเตอร์เป็นไม่แน่นอนในบริบทของฟังก์ชั่นในขณะที่มีinoutพารามิเตอร์ค่าของพารามิเตอร์ที่จุดของการกลับมาจะได้รับการคัดลอกออกมาจากฟังก์ชั่นและในบริบทของผู้โทร

วิธีที่ถูกต้องในการแก้ปัญหานี้คือการลบออกvarจากพารามิเตอร์และแนะนำvarตัวแปรโลคัล ที่ด้านบนของรูทีนให้คัดลอกค่าของพารามิเตอร์ลงในตัวแปรนั้น


44
ฉันไม่เข้าใจการเปลี่ยนแปลงนี้เลยทำไมต้องเขียนบรรทัดอื่นเพื่อสร้างตัวแปรท้องถิ่นที่เปลี่ยนแปลงได้จะดีกว่าการกำหนดพารามิเตอร์เป็น var
Ross Barbish

สำหรับฉันการเปลี่ยนแปลงนี้เป็นสิ่งที่ดีเพราะเป็นการหยิบสถานการณ์ที่ฉันควรใช้ตัวแปรท้องถิ่น แต่ฉันไม่ได้ทำเพราะฉันใช้วิธีง่ายๆและยอมรับคำแนะนำของ Swift (เก่า) ในการทำให้พารามิเตอร์อินพุตเป็นตัวแปร
วิด

1
ฉันกับ @RossBarbish ในเรื่องนี้ ดังนั้น ... สิ่งนี้ถูกลบออกเนื่องจากนักพัฒนาที่ขี้เกียจไม่สามารถแยกแยะระหว่างพารามิเตอร์ inout และ var Pfff ...
Danny Bravo

1
ดูเหมือนจะไม่จำเป็นอย่างยิ่ง ... พวกเขาควรจะมีทั้งสองทางเลือก
Oscar Gomez

1
อาจเป็นไปได้อย่างรวดเร็วคือการประกาศตัวแปรภายในของพารามิเตอร์ที่อยู่เบื้องหลังมากเกินไป ตอนนี้เราต้องทำด้วยตนเอง ไม่มีการเปลี่ยนแปลงในประสิทธิภาพ แต่เราสูญเสียความสะดวกสบายในการช่วยเหลือผู้เริ่มต้นด้วยแนวคิดง่ายๆ
mogelbuster

62

เพียงเพิ่มบรรทัดนี้ที่จุดเริ่มต้นของฟังก์ชัน:

var language = language

และส่วนที่เหลือของรหัสของคุณจะไม่เปลี่ยนแปลงเช่นนี้:

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
คำตอบที่ดีที่สุดโดยไกล ต้องเปลี่ยนบรรทัดเดียวเท่านั้น
BallpointBen

แต่ดูไม่เป็นธรรมชาติมาก
@James

1
ฉันรู้สึกว่านี่เป็นคำตอบที่ดีที่สุดเพราะยังคงชื่อเดิมไว้ คล้ายกับภาษาทั่วไปอื่น ๆ
eonist

1
@RiverSatya ทำไมไม่ใช้พารามิเตอร์โดยตรงล่ะ?
Declan McKenna

1
ข้อเสนอแนะที่ยอดเยี่ยมจริงๆ เราจะนำไปใช้ใน Swiftify :)
Crulex

13

ผู้คนจำนวนมากแนะนำinoutพารามิเตอร์ แต่นั่นไม่ใช่สิ่งที่ออกแบบมาเพื่อ นอกจากนี้ยังไม่อนุญาตให้เรียกฟังก์ชันด้วยletค่าคงที่หรือด้วยสตริงลิเทอรัล ทำไมคุณไม่เพียงเพิ่มค่าเริ่มต้นให้กับลายเซ็นฟังก์ชัน

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

ตรวจสอบให้แน่ใจว่าไม่ได้เรียกgetQuestionListด้วยสตริงว่างในกรณีที่คุณต้องการภาษาเริ่มต้น แต่ให้เว้นพารามิเตอร์ไว้:

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

3
ฉันก็ไม่เข้าใจเหมือนกันว่าทำไมทุกคนถึงใช้วิธีแก้ปัญหาเมื่อ OP ไม่ได้ใช้มันในตอนแรก ...
Eric Aya

1
พวกเขาสมมติว่า var และ inout ทำในสิ่งเดียวกัน
ryantxr

2

สวิฟต์ 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)

ในบางกรณีตามที่ฉันเคยสัมผัสมา (ด้วยการตั้งค่าที่ซับซ้อนมากขึ้นเกี่ยวกับอาร์เรย์) การสร้างคุณสมบัติใหม่ภายในเมธอดและการกลายพันธุ์คุณสมบัตินั้นอาจไม่ได้ผลเสมอไป ไม่ต้องพูดถึงคุณกำลังยุ่งกับวิธีการแทนที่จะต่อท้ายinoutพารามิเตอร์และ&อาร์กิวเมนต์ซึ่งเป็นสิ่งที่ไวยากรณ์นี้สร้างขึ้นเพื่อ



0

ฉันคิดว่าคำตอบของ @Harris และ @garanda เป็นแนวทางที่ดีที่สุด

อย่างไรก็ตามในกรณีของคุณไม่จำเป็นต้องมี var คุณสามารถทำได้:

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

พารามิเตอร์เข้า - ออก

พารามิเตอร์ฟังก์ชันเป็นค่าคงที่โดยค่าเริ่มต้น การพยายามเปลี่ยนค่าของพารามิเตอร์ฟังก์ชันจากภายในเนื้อความของฟังก์ชันนั้นส่งผลให้เกิดข้อผิดพลาดเวลาคอมไพล์ ซึ่งหมายความว่าคุณไม่สามารถเปลี่ยนค่าของพารามิเตอร์โดยไม่ได้ตั้งใจ หากคุณต้องการให้ฟังก์ชันแก้ไขค่าของพารามิเตอร์และคุณต้องการให้การเปลี่ยนแปลงเหล่านั้นคงอยู่หลังจากการเรียกฟังก์ชันสิ้นสุดลงให้กำหนดพารามิเตอร์นั้นเป็นพารามิเตอร์เข้า - ออกแทน

คุณเขียนพารามิเตอร์เข้า - ออกโดยวางคีย์เวิร์ด inout ก่อนประเภทของพารามิเตอร์ พารามิเตอร์เข้า - ออกมีค่าที่ส่งผ่านไปยังฟังก์ชันถูกแก้ไขโดยฟังก์ชันและถูกส่งกลับออกจากฟังก์ชันเพื่อแทนที่ค่าเดิม สำหรับการอภิปรายโดยละเอียดเกี่ยวกับลักษณะการทำงานของพารามิเตอร์เข้า - ออกและการปรับแต่งคอมไพลเลอร์ที่เกี่ยวข้องโปรดดูพารามิเตอร์เข้า - ออก

คุณสามารถส่งผ่านตัวแปรเป็นอาร์กิวเมนต์สำหรับพารามิเตอร์เข้า - ออกเท่านั้น คุณไม่สามารถส่งผ่านค่าคงที่หรือค่าตามตัวอักษรเป็นอาร์กิวเมนต์ได้เนื่องจากไม่สามารถแก้ไขค่าคงที่และค่าตามตัวอักษรได้ คุณวางเครื่องหมายแอมเพอร์แซนด์ (&) ไว้หน้าชื่อตัวแปรโดยตรงเมื่อคุณส่งเป็นอาร์กิวเมนต์ไปยังพารามิเตอร์เข้า - ออกเพื่อระบุว่าฟังก์ชันสามารถแก้ไขได้

บันทึก

พารามิเตอร์เข้า - ออกต้องไม่มีค่าเริ่มต้นและไม่สามารถทำเครื่องหมายพารามิเตอร์ตัวแปรเป็น inout ได้

นี่คือตัวอย่างของฟังก์ชันที่เรียกว่า swapTwoInts ( : :) ซึ่งมีพารามิเตอร์จำนวนเต็มสองตัวที่เรียกว่า a และ b:

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

ฟังก์ชัน swapTwoInts ( : :) เพียงแค่เปลี่ยนค่าของ b เป็น a และค่าของ a เป็น b ฟังก์ชันดำเนินการแลกเปลี่ยนนี้โดยการจัดเก็บค่าของ a ในค่าคงที่ชั่วคราวที่เรียกว่าชั่วคราว A กำหนดค่าของ b ให้กับ a แล้วกำหนดค่าชั่วคราว A ให้กับ b

คุณสามารถเรียกใช้ฟังก์ชัน swapTwoInts ( : :) โดยมีตัวแปรประเภท Int สองตัวแปรเพื่อสลับค่า โปรดสังเกตว่าชื่อของ someInt และ anotherInt จะนำหน้าด้วยเครื่องหมายและเมื่อส่งผ่านไปยังฟังก์ชัน 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"

ตัวอย่างด้านบนแสดงให้เห็นว่าค่าดั้งเดิมของ someInt และ anotherInt ถูกแก้ไขโดยฟังก์ชัน swapTwoInts ( : :) แม้ว่าเดิมจะถูกกำหนดไว้ภายนอกฟังก์ชัน

บันทึก

พารามิเตอร์เข้า - ออกไม่เหมือนกับการส่งคืนค่าจากฟังก์ชัน ตัวอย่าง swapTwoInts ด้านบนไม่ได้กำหนดประเภทการส่งคืนหรือส่งคืนค่า แต่ยังคงแก้ไขค่าของ someInt และ anotherInt พารามิเตอร์เข้า - ออกเป็นอีกทางเลือกหนึ่งสำหรับฟังก์ชันที่จะมีผลกระทบภายนอกขอบเขตของเนื้อหาฟังก์ชัน


0

นี่คือความคิดอื่น กรณีการใช้งานของฉันคือการส่งผ่านสตริงอาร์เรย์เพื่อต่อท้ายซึ่งอาร์เรย์จะต้องส่งต่อกัน ฉันไม่ต้องการมีสถานะในชั้นเรียนสำหรับเรื่องนี้เช่นกัน ผมจึงสร้างคลาสที่เก็บอาร์เรย์แล้วส่งผ่านไป ขึ้นอยู่กับกรณีการใช้งานของคุณอาจดูโง่ที่มีคลาสที่มีตัวแปรเพียงตัวเดียว

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

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

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

ฉันใช้appendและjoinedวิธีการในอาร์เรย์เท่านั้นดังนั้นจึงง่ายต่อการเปลี่ยนประเภทโดยมีการเปลี่ยนแปลงอื่น ๆ เล็กน้อยกับโค้ดของฉัน

ตัวอย่างการใช้งาน:

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
}

คำตอบของฉันคือถ้าคุณต้องการให้ค่าดั้งเดิมตามที่ผู้โทรเห็นต้องแก้ไข หากคุณเพียงแค่ต้องการกำหนดค่าใหม่ในเครื่อง แต่ไม่มีผลกับผู้โทรคำตอบอื่น ๆ ข้างต้นจะจัดการกับสิ่งนั้น
webjprgm
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.