ทำไมฉันถึงต้องมีการขีดเส้นใต้อย่างรวดเร็ว?


161

ที่นี่มีข้อความว่า "หมายเหตุ: ความ_หมาย" ฉันไม่สนใจคุณค่านั้น "" แต่มาจาก JavaScript ฉันไม่เข้าใจความหมายนั้น

วิธีเดียวที่ฉันจะได้รับฟังก์ชั่นการพิมพ์เหล่านี้คือการใช้เครื่องหมายขีดล่างหน้าพารามิเตอร์:

func divmod(_ a: Int, _ b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

print(divmod(7, 3))
print(divmod(5, 2))
print(divmod(12,4))

หากไม่มีขีดเส้นใต้ฉันต้องเขียนแบบนี้เพื่อหลีกเลี่ยงข้อผิดพลาด:

func divmod(a: Int, b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

print(divmod(a: 7, b: 3))
print(divmod(a: 5, b: 2))
print(divmod(a: 12,b: 4))

ฉันไม่เข้าใจการใช้ขีดล่างนี้ ฉันจะใช้เครื่องหมายขีดล่างเหล่านี้ได้อย่างไรและทำไมเมื่อใด

คำตอบ:


354

มีความแตกต่างเล็กน้อยในกรณีการใช้งานที่แตกต่างกัน แต่โดยทั่วไปแล้วขีดเส้นใต้หมายถึง "ละเว้นสิ่งนี้"


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

func myFunc(label name: Int) // call it like myFunc(label: 3)

"label" เป็นฉลากอาร์กิวเมนต์และจะต้องปรากฏเมื่อคุณเรียกใช้ฟังก์ชัน (และเนื่องจาก Swift 3 จำเป็นต้องใช้เลเบลสำหรับอาร์กิวเมนต์ทั้งหมดโดยค่าเริ่มต้น) "name" เป็นชื่อตัวแปรสำหรับอาร์กิวเมนต์ที่คุณใช้ภายในฟังก์ชัน แบบฟอร์มที่สั้นกว่ามีลักษณะดังนี้:

func myFunc(name: Int) // call it like myFunc(name: 3)

นี่คือช็อตคัตที่ให้คุณใช้คำเดียวกันสำหรับทั้งฉลากอาร์กิวเมนต์ภายนอกและชื่อพารามิเตอร์ภายใน func myFunc(name name: Int)มันเทียบเท่ากับ

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

func myFunc(_ name: Int) // call it like myFunc(3)

ในคำสั่งการมอบหมายขีดล่างหมายถึง "ไม่ได้กำหนดให้กับอะไร" คุณสามารถใช้ฟังก์ชันนี้หากคุณต้องการเรียกใช้ฟังก์ชันที่ส่งคืนผลลัพธ์ แต่ไม่สนใจค่าที่ส่งคืน

_ = someFunction()

หรือเช่นเดียวกับในบทความที่คุณเชื่อมโยงไปเพื่อละเว้นองค์ประกอบหนึ่งของ tuple ที่ส่งคืน:

let (x, _) = someFunctionThatReturnsXandY()

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

PHPhotoLibrary.performChanges( { /* some changes */ },
    completionHandler: { success, _ in // don't care about error
        if success { print("yay") }
    })

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

class MyView: NSView {
    override func mouseDown(with _: NSEvent) {
        // don't care about event, do same thing for every mouse down
    }
    override func draw(_ _: NSRect) {
        // don't care about dirty rect, always redraw the whole view
    }
}

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

for _ in 1...20 { // or 0..<20
    // do something 20 times
}

หากคุณกำลังเชื่อมโยงกรณี tuple ในคำสั่ง switch เครื่องหมายขีดเส้นใต้สามารถทำงานเป็น wildcard ดังในตัวอย่างนี้ (ย่อมาจากหนึ่งในภาษา Swift Programming ):

switch somePoint { // somePoint is an (Int, Int) tuple
case (0, 0):
    print("(0, 0) is at the origin")
case (_, 0):
    print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    print("(0, \(somePoint.1)) is on the y-axis")
default:
    print("(\(somePoint.0), \(somePoint.1)) isn't on an axis")
}

สิ่งสุดท้ายที่ไม่เกี่ยวข้องกันมาก แต่ที่ฉันจะรวมตั้งแต่ (ตามที่ระบุไว้โดยความคิดเห็น) ดูเหมือนว่าจะนำคนที่นี่: ขีดเส้นใต้ในตัวระบุ - เช่นvar _foo , func do_the_thing(), struct Stuff_- หมายถึงอะไรโดยเฉพาะสวิฟท์ แต่มีการใช้ไม่กี่ ในหมู่โปรแกรมเมอร์

เครื่องหมายขีดล่างภายในชื่อเป็นตัวเลือกสไตล์ แต่ไม่ต้องการในชุมชน Swift ซึ่งมีระเบียบแบบแผนเกี่ยวกับการใช้ UpperCamelCase สำหรับประเภทและ lowerCamelCase สำหรับสัญลักษณ์อื่น ๆ ทั้งหมด

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

สัญลักษณ์บางอย่างที่มีคำนำหน้าเครื่องหมายขีดล่างคู่ ( func __foo()) แฝงตัวอยู่ในส่วนลึกของ SDK ของ Apple: สัญลักษณ์เหล่านี้คือ (Obj) C ที่นำเข้าสู่ Swift โดยใช้NS_REFINED_FOR_SWIFTแอตทริบิวต์ การใช้แอปเปิ้ลว่าเมื่อพวกเขาต้องการที่จะทำให้ "มากกว่า Swifty" รุ่นของ (Obj) C API - ตัวอย่างเช่นเพื่อให้วิธีการประเภทไม่เชื่อเรื่องพระเจ้าเป็นวิธีการทั่วไป พวกเขาจำเป็นต้องใช้ API ที่นำเข้ามาเพื่อทำให้ Swift version ทำงานได้อย่างยอดเยี่ยมดังนั้นพวกเขาจึงใช้__เพื่อให้สามารถใช้งานได้ในขณะที่ซ่อนไว้จากเครื่องมือและเอกสารส่วนใหญ่


@ เคล็ดลับสิ่งที่มีความสำคัญของขีดเส้นใต้ที่จุดเริ่มต้นของวิธีการเช่นเดียวกับนี้ -> func _copyContents (เริ่มต้น ptr: UnsafeMutableBufferPointer <Element>) -> (Iterator, UnsafeMutableBufferPointer <Element>
dev gr

@devgr: ไม่เกี่ยวข้องกันโดยสิ้นเชิงดังนั้นฉันขอแนะนำให้โพสต์คำถามแยกต่างหาก
rickster

แน่นอนว่าฉันจะโพสต์คำถามแยกต่างหาก
dev gr

ขอบคุณที่ "ไม่ได้มอบหมายให้อะไร" สำหรับการส่งคืนฟังก์ชัน นี่คือสิ่งที่ฉันกำลังมองหา
absin

8

นอกเหนือจากคำตอบที่ยอมรับแล้วหนึ่งในกรณีการใช้งานของ _คือเมื่อคุณจำเป็นต้องเขียนหมายเลขยาวในรหัส

อ่านเพิ่มเติมหมายเลข

นี่ไม่ใช่มนุษย์อ่านง่าย:

let x = 1000000000000

คุณสามารถเพิ่ม _จำนวนเพื่อให้มนุษย์อ่านได้มากขึ้น:

let x = 1_000_000_000_000

6

ตั้งแต่ Swift 3 การระบุชื่อพารามิเตอร์ในการเรียกใช้ฟังก์ชันได้กลายเป็นสิ่งจำเป็น - แม้เป็นครั้งแรก ดังนั้นเนื่องจากอาจทำให้เกิดปัญหาใหญ่ในการเขียนโค้ดใน swift 2 คุณสามารถใช้เครื่องหมายขีดล่างที่การประกาศเพื่อป้องกันไม่ให้ต้องเขียนชื่อพารามิเตอร์ในการโทร ดังนั้นในกรณีนี้มันกำลังพูดว่า "ไม่สนใจชื่อพารามิเตอร์ภายนอก" โดยที่ชื่อพารามิเตอร์ภายนอกคือสิ่งที่คุณเรียกใช้พารามิเตอร์ภายนอกฟังก์ชั่น (เมื่อโทร) ไม่ได้อยู่ข้างใน ชื่อพารามิเตอร์ภายนอกเหล่านี้เรียกว่าอาร์กิวเมนต์ฉลาก http://ericasadun.com/2016/02/09/the-trouble-with-argument-labels-some- Thoughts/ ... ดูว่าพารามิเตอร์ได้รับชื่อสองชื่ออย่างไร อย่างแรกคือการที่ขีดเส้นใต้จะเกิดขึ้นหวังว่าสิ่งนี้จะช่วยได้และถามว่ายังสับสนอยู่ไหม


4
func divmod(_ a: Int, _ b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

func divmod(a: Int, b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

_เป็นตัวยึดสำหรับชื่อพารามิเตอร์ ในตัวอย่างของคุณคุณเรียกพวกเขาแตกต่างกันในฟังก์ชั่นที่สองคุณต้องเขียนชื่อพารามิเตอร์a: 1ในตัวอย่างของคุณเรียกพวกเขาแตกต่างกันในการทำงานที่สองคุณต้องเขียนชื่อพารามิเตอร์

แบบแผนชื่อฟังก์ชั่นของ Swift คือfuncName(param1:param2:)และมันต้องการ_ตัวยึดตำแหน่งเพื่อสร้างชื่อของฟังก์ชัน

ในชื่อแรกชื่อคือ

divmod(_:_:)

ในขณะที่สองคือ

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