`: _ *` (เครื่องหมายขีดเส้นใต้ของลำไส้ใหญ่) ทำอะไรในสกาลา?


195

ฉันมีรหัสต่อไปนี้จากคำถามนี้ :

def addChild(n: Node, newChild: Node) = n match {
  case Elem(prefix, label, attribs, scope, child @ _*) => Elem(prefix, label, attribs, scope, child ++ newChild : _*)
  case _ => error("Can only add children to elements!")
}

ทุกอย่างในนั้นค่อนข้างชัดเจนยกเว้นงานชิ้นนี้: child ++ newChild : _*

มันทำอะไร?

ฉันเข้าใจว่ามีการSeq[Node]ต่อกันกับผู้อื่นNodeแล้วใช่ไหม อะไร: _*ทำอย่างไร


70
ขอบคุณมากสำหรับการเพิ่ม (เครื่องหมายขีดล่างดาว) ไปที่ชื่อ!
Gal

คำตอบ:


151

มัน "splats" 1ลำดับ

ดูลายเซ็นตัวสร้าง

new Elem(prefix: String, label: String, attributes: MetaData, scope: NamespaceBinding,
         child: Node*)

ซึ่งเรียกว่าเป็น

new Elem(prefix, label, attributes, scope,
         child1, child2, ... childN)

แต่ที่นี่มีเพียงลำดับไม่child1, child2ฯลฯ ดังนั้นนี้จะช่วยให้ลำดับผลที่จะใช้เป็นข้อมูลในการสร้าง

การเข้ารหัสที่มีความสุข


1สิ่งนี้ไม่มีชื่อน่ารักใน SLS แต่นี่คือรายละเอียด สิ่งสำคัญที่จะได้รับคือมันเปลี่ยนวิธีที่สกาล่าผูกอาร์กิวเมนต์กับวิธีด้วยพารามิเตอร์ซ้ำ ๆ (ดังแสดงNode*ด้านบน)

_*ประเภทคำอธิบายประกอบจะครอบคลุมใน "4.6.2 พารามิเตอร์ซ้ำ" ของ SLS

พารามิเตอร์ค่าสุดท้ายของส่วนพารามิเตอร์อาจเป็น suf fi xed โดย“ *” เช่น (... , x: T *) ชนิดของพารามิเตอร์ที่ซ้ำกันภายในเมธอดนั้นเป็นชนิดลำดับลำดับ scala.Seq [T] วิธีการที่มีพารามิเตอร์ซ้ำแล้วซ้ำอีก T * รับจำนวนตัวแปรของอาร์กิวเมนต์ประเภท T นั่นคือถ้าเมธอด m ที่มีชนิด (p1: T1,..., pn: Tn, ps: S *) U ถูกนำไปใช้กับอาร์กิวเมนต์ (e1,....., ek) โดยที่ k> = n ดังนั้น m คือ ในแอพพลิเคชั่นนั้นจะมีประเภท (p1: T1,..., pn: Tn, ps: S,..., ps0S) U พร้อมกับ k ¡ n ที่เกิดขึ้นของประเภท S ที่ชื่อพารามิเตอร์ใด ๆข้อยกเว้นเดียวสำหรับกฎนี้คือถ้าอาร์กิวเมนต์สุดท้ายถูกทำเครื่องหมายเป็นอาร์กิวเมนต์ลำดับผ่านหมายเหตุประกอบชนิด _ * หาก m ข้างต้นถูกนำไปใช้กับข้อโต้แย้ง (e1,..., en, e0: _ *) ดังนั้นประเภทของ m ในแอปพลิเคชันนั้นจะถูกนำไปเป็น (p1: T1,...., pn: Tn, ps: scala .Seq [S])


5
เราต้องการที่จะเรียกมันว่า "จูบผู้ประกอบการ" แม้ว่ามันจะไม่ได้ดำเนินการจริง :)
เฮนริก Gustafsson

1
ใน Python สิ่งนี้เรียกว่าการเปิดออก
joshlk

มีข้อ จำกัด เกี่ยวกับระยะเวลาที่สามารถเรียงลำดับเช่นมีกับ varargs Java หรือไม่?
qwwqwwq

95
  • child ++ newChild - ลำดับ
  • : - ascription พิมพ์คำใบ้ที่ช่วยให้คอมไพเลอร์เข้าใจว่านิพจน์นั้นมีประเภทใด
  • _* - ตัวยึดตำแหน่งยอมรับค่าใด ๆ + ตัวดำเนินการ vararg

child ++ newChild : _*ขยายSeq[Node]ไปยังNode*(บอกคอมไพเลอร์ว่าเราค่อนข้างทำงานกับ varargs มากกว่าลำดับ) มีประโยชน์อย่างยิ่งสำหรับวิธีการที่สามารถยอมรับค่าต่าง ๆ ได้เท่านั้น


1
คุณช่วยเขียนเกี่ยวกับ "type ascription" เพิ่มเติมได้ไหม มันคืออะไรและมันทำงานอย่างไร
amorfis


24

คำตอบข้างต้นทั้งหมดดูดี แต่เพียงต้องการตัวอย่างเพื่ออธิบายสิ่งนี้ นี่มันคือ:

val x : Seq[Seq[Int]] = Seq(Seq(1),Seq(2))

def f(arg: Seq[Any]*) : Int = {
 arg.length
}
f(x) //1 as x is taken as single arg
f(x:_*)  // 2 as x is "unpacked" as a Seq[Any]*

ดังนั้นตอนนี้เรารู้ว่า:_*ต้องทำอย่างไรเพื่อบอกคอมไพเลอร์: โปรดแกะอาร์กิวเมนต์นี้และผูกองค์ประกอบเหล่านั้นเข้ากับพารามิเตอร์ vararg ในการเรียกใช้ฟังก์ชันแทนที่จะใช้ x เป็นอาร์กิวเมนต์เดี่ยว

ดังนั้นในสั้น ๆ:_*คือการลบความกำกวมเมื่อผ่านอาร์กิวเมนต์ไปที่พารามิเตอร์ vararg


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