พารามิเตอร์ทางเลือกเริ่มต้นในฟังก์ชัน Swift


108

เมื่อฉันตั้งค่าfirstThingเป็นค่าเริ่มต้นnilสิ่งนี้จะใช้งานได้โดยไม่มีค่าเริ่มต้นของnilฉันได้รับข้อผิดพลาดว่ามีพารามิเตอร์ที่ขาดหายไปเมื่อเรียกใช้ฟังก์ชัน

การพิมพ์Int?ฉันคิดว่ามันทำให้เป็นทางเลือกโดยมีค่าเริ่มต้นnilเป็นฉันใช่ไหม และถ้าเป็นเช่นนั้นทำไมจึงไม่ทำงานหากไม่มี= nil?

func test(firstThing: Int? = nil) {
    if firstThing != nil {
        print(firstThing!)
    }
    print("done")
}
test()

1
พิจารณาว่าคุณสามารถเขียนfunc test(firstThing: Int = 4): ไม่ใช่Optionalพารามิเตอร์ที่มีค่าเริ่มต้น Optionalประเภท (ซึ่งเป็นสิ่งที่?อยู่ในขยายชื่อชนิด) เป็นประเภทค่า; "พารามิเตอร์ที่เป็นทางเลือก" เป็นชื่อที่ไม่ดีสำหรับพารามิเตอร์ที่อาจมีหรือไม่มีอยู่ในการเรียกใช้ฟังก์ชันไม่ว่าจะเป็นประเภทใดก็ตาม
zneak

คุณใช้ Swift เวอร์ชันใดในการทดสอบโค้ดนี้ รหัสของคุณใช้ได้ดี !! ทางเลือกเป็นเพียงประเภทและพารามิเตอร์เริ่มต้นทำงานได้ดีเช่นเดียวกับประเภทอื่นใน Swift
Victor Sigler

คำตอบ:


211

ตัวเลือกและพารามิเตอร์เริ่มต้นเป็นสองสิ่งที่แตกต่างกัน

ตัวเลือกคือตัวแปรที่สามารถเป็นnilได้

พารามิเตอร์ดีฟอลต์ใช้ค่าดีฟอลต์เมื่อคุณละพารามิเตอร์นั้นค่าดีฟอลต์นี้ถูกระบุดังนี้:func test(param: Int = 0)

nilถ้าคุณระบุพารามิเตอร์ที่เป็นตัวเลือกที่คุณจะต้องให้มันแม้ว่าค่าที่คุณต้องการที่จะผ่านคือ หากฟังก์ชันของคุณมีลักษณะเช่นนี้func test(param: Int?)คุณจะไม่สามารถเรียกแบบนี้test()ได้ แม้ว่าพารามิเตอร์จะเป็นทางเลือก แต่ก็ไม่มีค่าเริ่มต้น

นอกจากนี้คุณยังสามารถรวมทั้งสองและมีพารามิเตอร์ที่จะเป็นตัวเลือกที่ต์เป็นค่าเริ่มต้นเช่นนี้nilfunc test(param: Int? = nil)


27
"หากคุณระบุพารามิเตอร์ที่เป็นทางเลือกคุณต้องระบุ" เยี่ยมมากขอบคุณ Swift
andrewtweber

8
@andrewtweber อารมณ์ขันของคุณเป็นที่ชื่นชม แต่สำหรับมือใหม่ฉันคิดว่าการชี้แจงว่า "ไม่บังคับ" หมายถึงการให้วัตถุหรือคุณค่าอาจเป็นประโยชน์ คุณไม่จำเป็นต้องทำเช่นนั้นคุณสามารถระบุ nil (ซึ่งแสดงถึงการไม่มีวัตถุหรือค่า) แทน คุณต้องตัดสินใจว่าคุณจะเลือกตัวเลือกใด
JD Sandifer

24

อาร์กิวเมนต์เริ่มต้นช่วยให้คุณสามารถเรียกใช้ฟังก์ชันได้โดยไม่ต้องผ่านอาร์กิวเมนต์ หากคุณไม่ผ่านอาร์กิวเมนต์จะมีการระบุอาร์กิวเมนต์เริ่มต้น ดังนั้นการใช้รหัสของคุณนี่ ...

test()

... เหมือนกับสิ่งนี้ทุกประการ:

test(nil)

หากคุณละทิ้งอาร์กิวเมนต์เริ่มต้นเช่นนี้ ...

func test(firstThing: Int?) {
    if firstThing != nil {
        print(firstThing!)
    }
    print("done")
}

... แล้วคุณจะทำสิ่งนี้ไม่ได้อีกต่อไป ...

test()

หากคุณทำเช่นนั้นคุณจะได้รับข้อผิดพลาด "อาร์กิวเมนต์ที่ขาดหายไป" ที่คุณอธิบายไว้ คุณต้องผ่านการโต้แย้งทุกครั้งแม้ว่าอาร์กิวเมนต์นั้นจะเป็นเพียงnil:

test(nil)   // this works

19

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

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

test(nil)หากคุณไม่ได้รวมค่าเริ่มต้นที่คุณจำเป็นต้องให้ค่าโทร:

นอกจากนี้และไม่เกี่ยวข้องโดยตรงกับคำถามนี้ แต่น่าจะคุ้มค่าที่จะทราบว่าคุณกำลังใช้วิธี "C ++" ในการจัดการกับพอยน์เตอร์ที่อาจเป็นค่าว่างเพื่อจัดการกับตัวเลือกศูนย์ที่เป็นไปได้ใน Swift รหัสต่อไปนี้ปลอดภัยกว่า (โดยเฉพาะในซอฟต์แวร์มัลติเธรด) และช่วยให้คุณหลีกเลี่ยงการบังคับให้แกะอุปกรณ์เสริม:

func test(firstThing: Int? = nil) {
    if let firstThing = firstThing {
        print(firstThing)
    }
    print("done")
}
test()

8

คุณกำลังสับสนOptionalกับการมีค่าเริ่มต้น Optionalยอมรับทั้งค่าหรือไม่มี การมีค่าเริ่มต้นอนุญาตให้ละเว้นอาร์กิวเมนต์ในการเรียกใช้ฟังก์ชัน อาร์กิวเมนต์สามารถมีค่าเริ่มต้นโดยมีหรือไม่มีOptionalประเภทก็ได้

func someFunc(param1: String?,
          param2: String = "default value",
          param3: String? = "also has default value") {
    print("param1 = \(param1)")

    print("param2 = \(param2)")

    print("param3 = \(param3)")
}

ตัวอย่างการโทรที่มีเอาต์พุต:

someFunc(param1: nil, param2: "specific value", param3: "also specific value")

param1 = nil
param2 = specific value
param3 = Optional("also specific value")

someFunc(param1: "has a value")

param1 = Optional("has a value")
param2 = default value
param3 = Optional("also has default value")

someFunc(param1: nil, param3: nil)

param1 = nil
param2 = default value
param3 = nil

สรุป:

  • พิมพ์ด้วย? (เช่น String?) Optionalอาจเป็นศูนย์หรืออาจมีอินสแตนซ์ของ Type
  • อาร์กิวเมนต์ที่มีค่าเริ่มต้นอาจถูกละเว้นจากการเรียกไปยังฟังก์ชันและจะใช้ค่าเริ่มต้น
  • หากทั้งคู่Optionalและมีค่าเริ่มต้นอาจถูกละเว้นจากการเรียกฟังก์ชันหรืออาจรวมและสามารถระบุด้วยค่าศูนย์ (เช่น param1: nil)

ฉันสามารถเพิ่มพารามิเตอร์เริ่มต้นเป็นตัวแปรเช่น let หรือ var ได้หรือไม่ ขอบคุณ
Yogesh Patel

@YogeshPatel ไม่แน่ใจว่าคุณหมายถึงอะไร
Chuck Krutsinger

เช่น var myName = "Yogesh" ตอนนี้ฟังก์ชันของฉันเหมือนกับ 1. func getFilterNames (name: string = myName) {} วิธีนี้ใช้ไม่ได้กับฉัน 2. func getFilterNames (name: string = "Yogesh") {} วิธีนี้ใช้ได้ผลสำหรับฉัน แต่ฉันต้องการคนแรกดังนั้นโปรดช่วยฉันทำสิ่งนี้ให้สำเร็จได้ไหม ขอบคุณมาก!
Yogesh Patel

@YogeshPatel ฉันคิดว่าสิ่งที่คุณต้องการคือfunc getFilterNames(name: inout String){ }สิ่งที่จะช่วยให้คุณแก้ไขชื่อที่ถูกส่งเข้ามาได้
Chuck Krutsinger

ไม่มีครับ. ฉันไม่ต้องการแก้ไขพารามิเตอร์ของฉัน ฉันแค่ต้องการให้ค่าเริ่มต้นกับพารามิเตอร์ของฉัน แต่ไม่เหมือนกับ "Yogesh" แบบคงที่ ฉันต้องการทำเช่น let name = "Yogesh" dynamic func getFilterNames (name: string = name) เช่นนี้ รับครับท่านนี้? ขอบคุณ!
Yogesh Patel

4

ในกรณีที่คุณจำเป็นต้องใช้พารามิเตอร์บูลคุณต้องกำหนดค่าเริ่มต้นเท่านั้น

func test(WithFlag flag: Bool = false){.....}

จากนั้นคุณสามารถใช้โดยไม่มีหรือกับพารามิเตอร์:

test() //here flag automatically has the default value: false
test(WithFlag: true) //here flag has the value: true

สำหรับคนที่โหวตลงคะแนนคุณสามารถแก้ไขสิ่งที่ผิดแทนเพื่อให้คนอื่นเข้าใจ
Niib Fouda

3

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

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


0

หากคุณต้องการให้สามารถเรียกfuncพารามิเตอร์โดยมีหรือไม่มีพารามิเตอร์คุณสามารถสร้างชื่อที่สองfuncของชื่อเดียวกันซึ่งเรียกอีกชื่อหนึ่งได้

func test(firstThing: Int?) {
    if firstThing != nil {
        print(firstThing!)
    }
    print("done")
}

func test() {
    test(firstThing: nil)
}

ตอนนี้คุณสามารถเรียกใช้ฟังก์ชันที่ตั้งชื่อtestโดยไม่มีหรือไม่มีพารามิเตอร์

// both work
test()
test(firstThing: 5)

เหตุใดคุณจึงกำหนดฟังก์ชันเพิ่มเติมในเมื่อคุณสามารถระบุ nil เป็นค่าเริ่มต้นสำหรับพารามิเตอร์ได้
Peter Schorn

-1

เป็นเรื่องยุ่งยากเล็กน้อยเมื่อคุณพยายามรวมพารามิเตอร์ทางเลือกและค่าเริ่มต้นสำหรับพารามิเตอร์นั้น แบบนี้,

func test(param: Int? = nil)

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

ดังนั้นจึงเป็นการดีกว่าเสมอที่จะไม่ใช้ nil เป็นค่าเริ่มต้น


1
สิ่งนี้ไม่ถูกต้อง ไม่มีอะไรผิดปกติกับตัวเลือกที่มีค่าเริ่มต้น (คู่nil)
Brian Kendig

สิ่งที่ฉันกำลังพูดคือเมื่อตัวแปรมีค่าเริ่มต้นมันไม่ใช่ทางเลือกในแง่ที่มันจะมีค่าเสมอไป
Shubham Naik

1
ไม่เป็นความจริงและฉันไม่แน่ใจว่าคุณพยายามอธิบายอะไร ฉันคิดว่าคุณพูดถูกต้องว่าเมื่อตัวแปรมีการกำหนดค่าแล้วตัวแปรนั้นจะถูกกำหนดเสมอ คุณไม่สามารถยกเลิกการมอบหมายได้ (และไม่ต้องการ) เว้นแต่คุณจะยกเลิกการจัดสรร และ Swift จะให้ข้อผิดพลาดในการคอมไพล์หากคุณพยายามใช้ตัวแปรก่อนที่จะมีค่า (เช่นเดียวกับในvar foo: String; print(foo)) แต่อาร์กิวเมนต์ของฟังก์ชันที่มีค่าดีฟอลต์เป็นอาร์กิวเมนต์ที่เป็นทางเลือก (คุณไม่จำเป็นต้องส่งผ่านในการเรียกฟังก์ชัน) และยังสามารถเป็นประเภทตัวเลือกได้อีกด้วย (อนุญาตให้nilกำหนดได้แม้จะเป็นค่าเริ่มต้น)
Brian Kendig

ทางเลือกเป็นพื้นฐานประเภทสหภาพของ <Type | ไม่มี> กล่าวคือสามารถมีชนิดที่ระบุหรือชนิดไม่มี (สมมติว่า swift มี Unions ซึ่งไม่มี แต่เรากำลังพูดถึงแนวคิดที่นี่) Int? = ศูนย์สมบูรณ์ดี
Shayne

-1

ค่าดีฟอลต์ไม่ได้หมายถึงค่าดีฟอลต์ของประเภทข้อมูลค่าดีฟอลต์ที่นี่หมายถึงค่าที่กำหนดในเวลาที่กำหนดฟังก์ชัน เราต้องประกาศค่าเริ่มต้นของตัวแปรในขณะที่กำหนดตัวแปรในฟังก์ชัน

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