ตัวแทน _ ขีดล่างในการอ้างอิง Swift คืออะไร


144

ในส่วนการอ้างอิงของเอกสารของ Apple มีตัวอย่างมากมายเช่น:

func runAction(_action: SKAction!)

Objective-C 'เทียบเท่า' ของสิ่งนี้คือ:

- (void)runAction:(SKAction *)action

มันทำให้ฉันรู้สึกว่ามันอาจเป็นสิ่งสำคัญที่ (ในการอ้างอิง Swift) มีช่องว่างหลังจากการขีดเส้นใต้และ "การกระทำ" ถูกเขียนเป็นตัวเอียง

แต่ฉันไม่สามารถเข้าใจได้ว่านี่คือสิ่งที่พยายามถ่ายทอด ดังนั้นบางทีคำถามคือ ... มีการอ้างอิงสำหรับการประชุมที่ใช้ในการอ้างอิงหรือไม่?

- นี่คือหน้าเว็บที่ฉันอ้างอิงในการอ้างอิงถึงการใช้ขีดล่าง: https://developer.apple.com/documentation/spritekit/sknode#//apple_ref/occ/instm/SKNode/runAction

ปรับปรุง

Swift 3 ได้ทำการเปลี่ยนแปลงบางอย่างเกี่ยวกับวิธีการใช้ชื่อและพารามิเตอร์ของฟังก์ชั่น / วิธีและป้ายชื่ออาร์กิวเมนต์ นี่เป็นข้อแยกย่อยสำหรับคำถามนี้และคำตอบ @Rickster ทำงานที่ยอดเยี่ยมในการตอบคำถามต่าง ๆ เกี่ยวกับ _underscores ในฟังก์ชั่นที่กำจัดสิ่งเหล่านี้ได้มากที่นี่: ทำไมฉันถึงต้องการขีดเส้นใต้อย่างรวดเร็ว?


3
ติดแท็กด้วย [underscore.js] ??
Martin R

3
เอกสารประกอบดังต่อไปนี้เป็นแบบแผนทางคณิตศาสตร์ของการใช้ตัวเอียงสำหรับชื่อตัวแปร ตัวอย่างเช่น: sin² a + cos² a = 1
rob mayoff

คำตอบ:


116

คำตอบทั้งสองถูกต้อง แต่ฉันต้องการชี้แจงเพิ่มเติมอีกเล็กน้อย

_จะใช้ในการปรับเปลี่ยนพฤติกรรมชื่อพารามิเตอร์ภายนอกสำหรับวิธีการ

ในส่วนชื่อโลคอลและพารามิเตอร์ภายนอกสำหรับเมธอดของเอกสารอธิบายว่า:

Swift ให้ชื่อพารามิเตอร์แรกในวิธีการชื่อพารามิเตอร์ท้องถิ่นโดยค่าเริ่มต้นและให้ชื่อพารามิเตอร์ที่สองและต่อมาทั้งชื่อพารามิเตอร์ท้องถิ่นและภายนอกโดยค่าเริ่มต้น

ในทางกลับกันฟังก์ชันตามค่าเริ่มต้นจะไม่มีชื่อพารามิเตอร์ภายนอก

ตัวอย่างเช่นเรามีfoo()วิธีนี้กำหนดไว้ในชั้นเรียนBar:

class Bar{
    func foo(s1: String, s2: String) -> String {
        return s1 + s2;
    }
}

เมื่อคุณเรียกจะเรียกว่าเหมือนfoo()bar.foo("Hello", s2: "World")

แต่คุณสามารถลบล้างพฤติกรรมนี้ได้โดยใช้_ด้านหน้าของs2ตำแหน่งที่ประกาศไว้

func foo(s1: String, _ s2: String) -> String{
    return s1 + s2;
}

จากนั้นเมื่อคุณโทรfooมันอาจจะเรียกง่ายๆว่าbar.foo("Hello", "World")ไม่มีชื่อของพารามิเตอร์ที่สอง

กลับไปที่กรณีของคุณrunActionเป็นวิธีการเพราะมันเกี่ยวข้องกับประเภทSKNodeอย่างชัดเจน ดังนั้นการวาง_พารามิเตอร์ before actionช่วยให้คุณสามารถโทรได้runActionโดยไม่มีชื่อภายนอก

อัปเดตสำหรับ Swift 2.0

ขณะนี้ฟังก์ชั่นและวิธีการทำงานในลักษณะเดียวกันการประกาศชื่ออาร์กิวเมนต์ภายในและภายนอก

ตอนนี้ฟังก์ชั่นถูกเรียกโดยใช้ชื่อพารามิเตอร์ภายนอกโดยค่าเริ่มต้นเริ่มต้นที่พารามิเตอร์ที่ 2 กฎนี้ใช้กับรหัส Swift ที่แท้จริงเท่านั้น

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


9
สับสนถ้า_เขียนก่อนพารามิเตอร์ที่สองคำตอบของคุณชัดเจนเพียงพอ จะเกิดอะไรขึ้นถ้าในfunc runAction(_action: SKAction!)นั้น_คือก่อนพารามิเตอร์แรกหรือถ้าคุณเขียนรหัสfunc foo(_ s1: String) { // your code }Xcode ต่อไปนี้ จะให้คำเตือน แต่มีรหัสจำนวนมากเช่นfunc bringSubviewToFront(_ view: UIView)ในการอ้างอิงทำไม?
Will Zhang

10
โดยพื้นฐานแล้วมันทำสิ่งนี้โดยไม่มีเหตุผลและทำให้ทุกคนสับสน น่ากลัว
botbot

2
ขีดล่างเป็นที่รู้จักกันในชื่อว่า 'Wildcard Pattern' developer.apple.com/library/ios/documentation/Swift/Conceptual/…
user2143356

@Wayatt Zhang หมอกล่าวว่าการใช้_พารามิเตอร์แรกนั้นไม่เกี่ยวข้อง ฉันสามารถสันนิษฐานได้ว่านักออกแบบคิดว่ามันชัดเจนเพียงพอสำหรับโค้ดของคุณและไม่ทำให้อ่านง่าย แต่ในทางกลับกันมันมีรหัส ดังนั้นคุณจะได้รับคำเตือน การอ้างอิงมีเป้าหมายตรงกันข้าม: จะต้องชัดเจนที่สุดเท่าที่จะเป็นไปได้ดังนั้นการขีดเส้นใต้ของพารามิเตอร์ตัวแรกจึงถูกกล่าวถึงสำหรับเมธอด EVERY นั่นจะอธิบายทุกอย่าง)
Dmitry Gryazin

4
สิ่งสำคัญคือต้องทราบว่า Swift 3.0 เปลี่ยนแปลงสิ่งต่าง ๆ ต้องใช้ป้ายกำกับทั้งหมดยกเว้นว่าคุณระบุเป็นอย่างอื่น ดังนั้น-พารามิเตอร์ก่อนหน้านี้จึงไม่เกิดขึ้นอีกแล้ว ตัวอย่างเช่น: override func viewWillAppear(_ animated: Bool)ส่งสัญญาณว่าผู้เรียก (รหัส Objective-C) จะไม่ใช้ป้ายกำกับพารามิเตอร์
Mr. T

85

ขีดล่างเป็นโทเค็นทั่วไปที่ใช้เพื่อระบุค่าที่ถูกทิ้ง

ในกรณีเฉพาะนี้หมายความว่าฟังก์ชันจะถูกเรียกใช้runAction(argument)แทนrunAction(action:argument)

ในบริบทอื่น ๆ มีความหมายคล้ายกันเช่นใน:

for _ in 0..<5 { ... }

หมายความว่าเราเพียงต้องการรันบล็อก 5 ครั้งและเราไม่สนใจเกี่ยวกับดัชนีในบล็อก

ในบริบทนี้:

let (result, _) = someFunctionThatReturnsATuple()

หมายความว่าเราไม่สนใจว่าองค์ประกอบที่สองของ tuple คืออะไรเพียงแค่สิ่งแรก


ดังนั้นในกรณีนี้การโต้แย้ง (การกระทำ) เป็นตัวเลือก?
สับสน

1
ไม่มันทำให้ชื่อพารามิเตอร์ภายนอก (การกระทำ :) ในกรณีนี้เป็นค่าว่างจึงถูกละเว้น อาร์กิวเมนต์ยังต้องการ แต่ก็ไม่ได้ติดแท็กการกระทำ:
David Berry

4
คำตอบที่แท้จริงคือการรวมกันของคำตอบและของ @dasblinkenlight เขาพูดถึงกรณีเฉพาะนี้อย่างแม่นยำมากขึ้นในขณะที่ฉันตอบคำถามที่กว้างขึ้น _ หมายความว่าอย่างไร
David Berry

4
คุณสามารถใช้เครื่องหมายทิ้งสำหรับตัวเลขจำนวนมากเพื่อให้อ่านง่ายขึ้นเช่นนี้let pi = 3.141_592_653_59
SMP

น่าขบขันคุณยังสามารถใช้มันเพื่อทำให้ตัวเลขที่มีขนาดใหญ่มากอ่านได้น้อยลงเช่นlet pi = 3.1_4_15_92___63
David Berry

15

ตั้งแต่สวิฟท์ 3ป้ายอาร์กิวเมนต์ทั้งหมดจะต้องเริ่มต้น

คุณสามารถบังคับให้มีการ IDE _เพื่อซ่อนป้ายโต้เถียงกับ

func foo(a: String) {
}

func foo2(_ a: String) {
}

เรียกว่าfoo(a: "abc")และfoo2("abc")

หมายเหตุ:สามารถใช้งานได้เฉพาะเมื่อaเป็นชื่อตัวแปรอาร์กิวเมนต์ (ภายนอก)และ(ภายใน) ตัวแปรในเวลาเดียวกัน มันเทียบเท่า - จะไม่ยอมรับfunc foo(a a: String)_

ทำไม Apple ถึงใช้มัน

คุณสามารถเห็น Apple กำลังใช้งานมันข้าม API ไลบรารีของ Apple ยังคงเขียนใน Objective-C (หากไม่ใช่พวกมันจะใช้ชื่อฟังก์ชั่นเดียวกันร่วมกันซึ่งถูกออกแบบมาสำหรับไวยากรณ์ Objective-C)

ฟังก์ชั่นที่ต้องการapplicationWillResignActive(_ application: UIApplication)จะมีชื่อพารามิเตอร์ซ้ำซ้อนapplicationเนื่องจากมีแอปพลิเคชันในชื่อฟังก์ชันอยู่แล้ว

ตัวอย่างของคุณ

func runAction(_ action: SKAction!)จะเรียกว่าได้โดยไม่ต้องเป็นของเครื่องหมายเช่น_ runAction(action:)ชื่อพารามิเตอร์actionจะซ้ำซ้อนเนื่องจากมีอยู่แล้วในชื่อฟังก์ชัน นั่นคือจุดประสงค์และทำไมมันถึงอยู่ที่นั่น


13

ตัวบ่งชี้ด้านหน้าของการประกาศพารามิเตอร์กำหนดชื่อพารามิเตอร์ภายนอก นี่คือชื่อที่ผู้โทรต้องให้เมื่อเรียกใช้ฟังก์ชัน:

func someFunction(externalParameterName localParameterName: Int)

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

คุณสามารถยกเลิกพฤติกรรมนี้โดยการขีดเส้นใต้ ( _) แทนชื่อภายนอกที่ชัดเจนเมื่อคุณกำหนดพารามิเตอร์

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับพฤติกรรมนี้ในส่วนที่เกี่ยวกับชื่อภายนอกสำหรับพารามิเตอร์ที่มีค่าเริ่มต้น ที่นี่


ดังนั้น ... ขอผมดูหน่อยว่าความมัวของผมนั้นถูกต้องไหม ในตัวอย่างนี้ฉันควรตั้งชื่อตัวแปร / ค่าคงที่เป็น "การกระทำ" และกำหนดให้ SKAction ที่ฉันต้องการเรียกใช้โดยฟังก์ชันนี้และ Swift ตั้งชื่อพารามิเตอร์เริ่มต้น "การกระทำ" ที่ต้องการโดยอัตโนมัติ อย่างไรก็ตามถ้าฉันต้องการตั้งชื่อการกระทำนี้ฉันต้องใช้ขีดล่างในการเรียกใช้ฟังก์ชันหรือไม่
สับสน

4
@Confused ความเข้าใจของฉันคือSKนักออกแบบของไม่ต้องการให้คุณเขียนactionสองครั้งเพราะ "การกระทำ" เป็นส่วนหนึ่งของชื่อฟังก์ชั่นแล้ว ในคำอื่น ๆ sprite.runAction(action:moveGroundSpritesForever)ที่พวกเขาไม่ต้องการให้คุณเขียน วัตถุประสงค์ของชื่อพารามิเตอร์ภายนอกคือการทำให้รหัสของคุณ "อ่านเหมือนประโยค"; ใช้actionสองครั้งจะเอาชนะวัตถุประสงค์ของการที่
dasblinkenlight

ไฟบางดวงยังอยู่ในความมืด ฉันคิดว่าฉันได้รับมัน คุณสมบัติของภาษานี้มีวัตถุประสงค์เพื่อให้ฟังก์ชั่นการโทรใน Swift มีลักษณะเหมือนวิธีที่คุณใช้เรียกวิธีการที่มีพารามิเตอร์ใน Objective-C อาจจะ.
สับสน

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

ดังนั้น ... ในระยะสั้นมันสลับระหว่างพารามิเตอร์ที่มีชื่อและพารามิเตอร์ลำดับดังนั้นคุณสามารถสลับระหว่าง foo.bar(param: 'fiddle') และ foo.bar('fiddle') หมายเหตุ: ด้วยการโต้แย้งเพียงครั้งเดียวมันจะไม่ปรากฏชัดเจน ... แต่ด้วยการขัดแย้งหลายครั้งมันจะกลายเป็นเรื่องที่เกี่ยวข้องมาก: foo.bar(param1: 'fiddle', param2: 'dee') vs foo.bar('fiddle','dee')
jrypkahauer

10

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

- (void)myFancyMethodWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName;

[someInstance myFancyMethodWithFirstName:@"John" lastName:@"Doe"];

เพื่อให้การเรียก Swift api สอดคล้องกับ objc คุณจะต้องระงับชื่อพารามิเตอร์ภายนอกของพารามิเตอร์แรก

func myFancyMethodWithFirstName(_ firstName:String, lastName:String);

someInstance.myFancyMethodWithFirstName("John", lastName:"Doe")

2
ฉันชอบคำอธิบายนี้ เมื่อเรียนรู้ Obj-C ก่อนคุณจะได้ล้างสิ่งต่างๆ นอกจากนี้ยังเน้นถึงความสำคัญของการตั้งชื่อวิธีการอย่างเหมาะสมใน Swift กล่าวคือส่วนหลังของชื่อเมธอดควรอธิบายอาร์กิวเมนต์แรกเช่นเดียวกับกรณีใน Obj-C สิ่งที่ดี.
rrrrrraul

5

ที่จริงแล้วมีความแตกต่างระหว่างรหัสจริงที่ใช้ในการกำหนดวิธีการและวิธีการประกาศในเอกสารของ Apple มาลองใช้UIControl 's - addTarget: action: forControlEvents:เมธอดตัวอย่างโค้ดจริงคือ: ป้อนคำอธิบายรูปภาพที่นี่

แต่ในเอกสารจะมีลักษณะเช่นนี้ (สังเกต _ ก่อนถึงเป้าหมาย): ป้อนคำอธิบายรูปภาพที่นี่

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

ไม่มีชื่อภายนอกเมื่อฟังก์ชันถูกเรียกใช้โดยค่าเริ่มต้นเว้นแต่คุณจะให้ชื่อของคุณเองหรือเพิ่ม # ก่อน (ไม่มีช่องว่าง) ชื่อท้องถิ่นของพารามิเตอร์ตัวอย่างเช่นนี่คือวิธีที่เราใช้dispatch_after : ป้อนคำอธิบายรูปภาพที่นี่

และในเอกสารดูเหมือนว่านี่ (สังเกตเห็นสาม _): ป้อนคำอธิบายรูปภาพที่นี่

หลักการของการประกาศฟังก์ชั่นนั้นเหมือนกับที่ฉันได้อธิบายไว้สำหรับวิธีการ


1

มองเห็นได้มากขึ้น

ป้อนคำอธิบายรูปภาพที่นี่

ในขณะที่คุณสามารถเห็น_เพียงแค่ทำให้ละเว้นชื่อพารามิเตอร์ท้องถิ่นหรือไม่

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