อะไรคือกฎที่แน่นอนเมื่อคุณสามารถละเว้นวงเล็บจุดวงเล็บปีกกา = (ฟังก์ชัน) ฯลฯ ได้


106

อะไรคือกฎที่แม่นยำเมื่อคุณสามารถละเว้น (ละเว้น) วงเล็บจุดวงเล็บปีกกา = (ฟังก์ชัน) ฯลฯ ได้

ตัวอย่างเช่น,

(service.findAllPresentations.get.first.votes.size) must be equalTo(2).
  • service เป็นวัตถุของฉัน
  • def findAllPresentations: Option[List[Presentation]]
  • votes ผลตอบแทน List[Vote]
  • ต้องและจะมีฟังก์ชั่นทั้งสองรายละเอียด

ทำไมฉันไปไม่ได้:

(service findAllPresentations get first votes size) must be equalTo(2)

เหรอ?

ข้อผิดพลาดของคอมไพเลอร์คือ:

"RestServicesSpecTest.this.service.findAllPresentations ประเภทตัวเลือก [รายการ [com.sharca.Presentation]] ไม่ใช้พารามิเตอร์"

เหตุใดจึงคิดว่าฉันกำลังพยายามส่งผ่านพารามิเตอร์ เหตุใดฉันจึงต้องใช้จุดสำหรับการเรียกทุกวิธี

ทำไมต้อง(service.findAllPresentations get first votes size)เท่ากันถึง (2) ส่งผลให้:

"not found: value first"

แต่ "ต้องเท่ากันถึง 2" ของ (service.findAllPresentations.get.first.votes.size)ต้องเท่ากับ 2 นั่นคือการต่อสายวิธีทำงานได้ดี? - พาราโซ่ห่วงโซ่วัตถุ

ฉันได้ดูหนังสือและเว็บไซต์ของ Scala แล้วและไม่สามารถหาคำอธิบายที่ครอบคลุมได้

จริงๆแล้วดังที่ Rob H อธิบายไว้ในคำถาม Stack Overflow อักขระใดที่ฉันสามารถละเว้นใน Scala ได้ ซึ่งเป็นกรณีการใช้งานที่ถูกต้องเท่านั้นสำหรับการละเว้น "." มีไว้สำหรับการดำเนินการรูปแบบ "ตัวดำเนินการตัวถูกดำเนินการตัวถูกดำเนินการ" และไม่ใช่สำหรับการเชื่อมโยงวิธีการ

คำตอบ:


87

ดูเหมือนคุณจะสะดุดกับคำตอบ อย่างไรก็ตามฉันจะพยายามทำให้ชัดเจน

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

ตอนนี้สัญกรณ์ตัวดำเนินการเป็นสัญกรณ์สำหรับการเรียกวิธีการซึ่งหมายความว่าไม่สามารถใช้ในกรณีที่ไม่มีวัตถุที่กำลังถูกเรียก

ฉันจะอธิบายรายละเอียดโดยย่อ

คำนำหน้า:

เพียง~, !, +และ-สามารถนำมาใช้ในคำนำหน้าสัญกรณ์ นี่คือสัญกรณ์ที่คุณใช้เมื่อคุณเขียนหรือ!flagval liability = -debt

Infix:

นั่นคือสัญกรณ์ที่วิธีการปรากฏระหว่างออบเจ็กต์และพารามิเตอร์ของมัน ตัวดำเนินการเลขคณิตทั้งหมดพอดีที่นี่

Postfix (คำต่อท้ายด้วย):

สัญกรณ์ที่จะใช้เมื่อวิธีการดังต่อไปนี้วัตถุและได้รับไม่มีพารามิเตอร์ ตัวอย่างเช่นคุณสามารถเขียนlist tailและนั่นคือสัญกรณ์ postfix

คุณสามารถเชื่อมต่อการเรียกสัญกรณ์ infix ได้โดยไม่มีปัญหาตราบเท่าที่ไม่มีวิธีใดที่โค้งงอ ตัวอย่างเช่นฉันชอบใช้สไตล์ต่อไปนี้:

(list
 filter (...)
 map (...)
 mkString ", "
)

นั่นคือสิ่งเดียวกับ:

list filter (...) map (...) mkString ", "

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

คุณสามารถใช้ infix กับพารามิเตอร์หลายตัว:

string substring (start, end) map (_ toInt) mkString ("<", ", ", ">")

ฟังก์ชั่น Curried นั้นยากที่จะใช้กับสัญลักษณ์ infix ฟังก์ชั่นการพับเป็นตัวอย่างที่ชัดเจนว่า:

(0 /: list) ((cnt, string) => cnt + string.size)
(list foldLeft 0) ((cnt, string) => cnt + string.size)

คุณต้องใช้วงเล็บนอกการเรียก infix ฉันไม่แน่ใจว่ากฎที่แน่นอนในการเล่นที่นี่

ตอนนี้เรามาพูดถึง postfix Postfix สามารถยากที่จะใช้เพราะมันไม่สามารถใช้งานได้ทุกที่ยกเว้นในตอนท้ายของการแสดงออก ตัวอย่างเช่นคุณไม่สามารถทำสิ่งต่อไปนี้:

 list tail map (...)

เนื่องจาก tail ไม่ปรากฏที่ส่วนท้ายของนิพจน์. คุณไม่สามารถทำได้:

 list tail length

คุณสามารถใช้สัญกรณ์ infix ได้โดยใช้วงเล็บเพื่อทำเครื่องหมายจุดสิ้นสุดของนิพจน์:

 (list tail) map (...)
 (list tail) length

หมายเหตุสัญกรณ์ postfix ที่ท้อแท้เพราะมันอาจจะไม่ปลอดภัย

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


อ่าคุณกำลังบอกว่าในคำสั่งของฉัน: ((((((realService findAllPresentations) get) first) votes) size) ต้องเท่ากับ 2 - get, first, votes และ size เป็นตัวดำเนินการ postfix ทั้งหมดเนื่องจากไม่มีพารามิเตอร์ เหรอ? ดังนั้นฉันจึงสงสัยว่าอะไรต้องเป็นและเท่ากันถึงจะเป็น ...
Antony Stubbs

ฉันพูดอะไรไม่ออกแม้ว่าฉันค่อนข้างมั่นใจว่าต้องเป็นอย่างนั้น :-) "be" น่าจะเป็นวัตถุตัวช่วยเพื่อให้ไวยากรณ์สวยขึ้น หรือโดยเฉพาะอย่างยิ่งในการเปิดใช้งานการใช้สัญลักษณ์ infix ด้วย "must"
Daniel C. Sobral

สิ่งที่ได้รับคือ Option.get อันดับแรกคือ list อันดับแรกโหวตเป็นคุณสมบัติของคลาสเคสและขนาดคือ list.size ตอนนี้คุณคิดยังไง?
Antony Stubbs

อ่าใช่ - ทั้งหมดนี้ได้รับการเสริมด้วยข้อเท็จจริงที่ว่า "(realService findPresentation 1) .get.id ต้องเท่ากันถึง 1" ทำงาน - เนื่องจาก Service # findPresentations (id: Int) เป็นตัวดำเนินการ infix ที่ดูเหมือน เจ๋ง - ฉันคิดว่าฉันเข้าใจแล้ว :)
Antony Stubbs

42

คำจำกัดความของคลาส:

valหรือvarสามารถละเว้นจากพารามิเตอร์คลาสซึ่งจะทำให้พารามิเตอร์เป็นส่วนตัว

การเพิ่ม var หรือ val จะทำให้เป็นแบบสาธารณะ (นั่นคือมีการสร้างตัวเข้าถึงเมธอดและตัวเปลี่ยนค่า)

{} สามารถละเว้นได้หากชั้นเรียนไม่มีเนื้อความนั่นคือ

class EmptyClass

การสร้างอินสแตนซ์ของคลาส:

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

class D[T](val x:T, val y:T);

สิ่งนี้จะทำให้คุณมีข้อผิดพลาดประเภท(พบ Int, สตริงที่คาดหวัง)

var zz = new D[String]("Hi1", 1) // type error

ในขณะที่ใช้งานได้ดี:

var z = new D("Hi1", 1)
== D{def x: Any; def y: Any}

เนื่องจากพารามิเตอร์ type T ถูกอนุมานว่าเป็น supertype ทั่วไปที่น้อยที่สุดของทั้งสอง - Any


คำจำกัดความของฟังก์ชัน:

= สามารถทิ้งได้หากฟังก์ชันส่งคืนหน่วย (ไม่มีอะไร)

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

def returnAString = "Hi!"

แต่ไม่ได้ผล:

def returnAString "Hi!" // Compile error - '=' expected but string literal found."

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

() สามารถทิ้งได้หากฟังก์ชันไม่ใช้อาร์กิวเมนต์ใด ๆ นั่นคือ

def endOfString {
  return "myDog".substring(2,1)
}

ซึ่งตามอนุสัญญาสงวนไว้สำหรับวิธีการที่ไม่มีผลข้างเคียง - เพิ่มเติมในภายหลัง

()ไม่ได้ลดลงตามความเป็นจริงเมื่อกำหนดชื่อ paramenter แต่จริงๆแล้วมันเป็นสัญกรณ์ที่แตกต่างกันทางความหมายนั่นคือ

def myOp(passByNameString: => String)

กล่าวว่า myOp รับพารามิเตอร์ pass-by-name ซึ่งส่งผลให้สตริง (นั่นคืออาจเป็นบล็อกรหัสที่ส่งคืนสตริง) ซึ่งตรงข้ามกับพารามิเตอร์ฟังก์ชัน

def myOp(functionParam: () => String)

ซึ่งบอกว่าmyOpรับฟังก์ชันที่มีพารามิเตอร์เป็นศูนย์และส่งคืนสตริง

(โปรดทราบว่าพารามิเตอร์ pass-by-name จะรวบรวมเป็นฟังก์ชันมันทำให้ไวยากรณ์ดีขึ้นเท่านั้น)

() สามารถลดลงในนิยามพารามิเตอร์ของฟังก์ชันหากฟังก์ชันรับอาร์กิวเมนต์เดียวเท่านั้นตัวอย่างเช่น:

def myOp2(passByNameString:(Int) => String) { .. } // - You can drop the ()
def myOp2(passByNameString:Int => String) { .. }

แต่ถ้าต้องใช้มากกว่าหนึ่งอาร์กิวเมนต์คุณต้องใส่ ():

def myOp2(passByNameString:(Int, String) => String) { .. }

งบ:

.สามารถลดลงเพื่อใช้สัญกรณ์ตัวดำเนินการซึ่งสามารถใช้ได้เฉพาะกับตัวดำเนินการ infix (ตัวดำเนินการของวิธีการที่ใช้อาร์กิวเมนต์) ดูคำตอบของ Danielสำหรับข้อมูลเพิ่มเติม

  • . นอกจากนี้ยังสามารถทิ้งไว้สำหรับหางรายการฟังก์ชัน postfix

  • () สามารถทิ้งไว้สำหรับ postfix operator list.tail

  • () ไม่สามารถใช้กับวิธีการที่กำหนดเป็น:

    def aMethod = "hi!" // Missing () on method definition
    aMethod // Works
    aMethod() // Compile error when calling method

เนื่องจากสัญกรณ์นี้สงวนไว้โดยแบบแผนสำหรับวิธีการที่ไม่มีผลข้างเคียงเช่น List # tail (นั่นคือการเรียกใช้ฟังก์ชันที่ไม่มีผลข้างเคียงหมายความว่าฟังก์ชันนั้นไม่มีผลที่สังเกตได้ยกเว้นค่าที่ส่งคืน)

  • () สามารถทิ้งสัญกรณ์ตัวดำเนินการเมื่อส่งผ่านในอาร์กิวเมนต์เดียว

  • () อาจจำเป็นต้องใช้ตัวดำเนินการ postfix ซึ่งไม่ได้อยู่ที่ส่วนท้ายของคำสั่ง

  • () อาจจำเป็นต้องกำหนดคำสั่งซ้อนการสิ้นสุดของฟังก์ชันที่ไม่ระบุตัวตนหรือสำหรับตัวดำเนินการที่ใช้พารามิเตอร์มากกว่าหนึ่งตัว

เมื่อเรียกใช้ฟังก์ชันที่รับฟังก์ชันคุณไม่สามารถละเว้น () จากนิยามฟังก์ชันภายในตัวอย่างเช่น:

def myOp3(paramFunc0:() => String) {
    println(paramFunc0)
}
myOp3(() => "myop3") // Works
myOp3(=> "myop3") // Doesn't work

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

def myOp2(passByNameString:Int => String) {
  println(passByNameString)
}

คุณต้องเรียกมันว่า:

myOp("myop3")

หรือ

myOp({
  val source = sourceProvider.source
  val p = myObject.findNameFromSource(source)
  p
})

แต่ไม่:

myOp(() => "myop3") // Doesn't work

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

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


10
ฉันกำลังร้องไห้. นี่คืออะไร.
Profpatsch

12

ชุดคำพูดที่ให้ข้อมูลเชิงลึกเกี่ยวกับเงื่อนไขต่างๆ ...

โดยส่วนตัวฉันคิดว่าจะมีอะไรมากกว่านี้ในสเปค ฉันแน่ใจว่าต้องมีฉันแค่ไม่ได้ค้นหาคำที่เหมาะสม ...

อย่างไรก็ตามมีแหล่งข้อมูลสองสามแหล่งและฉันได้รวบรวมไว้ด้วยกัน แต่ไม่มีอะไรที่สมบูรณ์ / ครอบคลุม / เข้าใจได้ / ที่อธิบายปัญหาข้างต้นให้ฉัน ... :

"ถ้าเนื้อความของเมธอดมีมากกว่าหนึ่งนิพจน์คุณต้องล้อมรอบด้วยเครื่องหมายปีกกา {…} คุณสามารถละเว้นวงเล็บปีกกาได้หากเนื้อความของเมธอดมีเพียงนิพจน์เดียว"

จากบทที่ 2 "Type Less, Do More" ของProgramming Scala :

"เนื้อความของเมธอดส่วนบนมาหลังเครื่องหมายเท่ากับ '=' ทำไมจึงเป็นเครื่องหมายเท่ากับทำไมไม่ใช้เพียงวงเล็บปีกกา {…} เหมือนใน Java เพราะอัฒภาคประเภทการคืนฟังก์ชันรายการอาร์กิวเมนต์ของเมธอดและแม้แต่วงเล็บปีกกา ในบางครั้งการใช้เครื่องหมายเท่ากับจะช่วยป้องกันไม่ให้เกิดความคลุมเครือในการแยกวิเคราะห์ที่เป็นไปได้หลายประการการใช้เครื่องหมายเท่ากับยังช่วยเตือนเราด้วยว่าแม้แต่ฟังก์ชันก็เป็นค่าใน Scala ซึ่งสอดคล้องกับการสนับสนุนการเขียนโปรแกรมเชิงฟังก์ชันของ Scala ซึ่งอธิบายไว้ในรายละเอียดเพิ่มเติมในบทที่ 8 การเขียนโปรแกรมฟังก์ชันใน สกาล่า”

จากบทที่ 1 "Zero to Sixty: Introduction Scala" ของProgramming Scala :

"ฟังก์ชันที่ไม่มีพารามิเตอร์สามารถประกาศได้โดยไม่มีวงเล็บซึ่งในกรณีนี้จะต้องถูกเรียกโดยไม่มีวงเล็บสิ่งนี้ให้การสนับสนุนสำหรับ Uniform Access Principle เช่นผู้เรียกไม่ทราบว่าสัญลักษณ์เป็นตัวแปรหรือฟังก์ชันที่ไม่มี พารามิเตอร์

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

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

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

และเนื่องจากคุณสามารถใช้วงเล็บปีกกาได้ทุกที่ที่คุณสามารถใช้วงเล็บได้คุณจึงสามารถละเว้นจุดและใส่เครื่องหมายวงเล็บซึ่งอาจมีหลายข้อความ

สามารถเรียกใช้ฟังก์ชันที่ไม่มีอาร์กิวเมนต์ได้โดยไม่มีวงเล็บ ตัวอย่างเช่นฟังก์ชัน length () บน String สามารถเรียกใช้เป็น "abc" .length แทนที่จะเป็น "abc" .length () ถ้าฟังก์ชันเป็นฟังก์ชัน Scala ที่กำหนดโดยไม่มีวงเล็บดังนั้นฟังก์ชันจะต้องถูกเรียกใช้โดยไม่มีวงเล็บ

ตามแบบแผนฟังก์ชันที่ไม่มีอาร์กิวเมนต์ที่มีผลข้างเคียงเช่น println จะถูกเรียกด้วยวงเล็บ ผู้ที่ไม่มีผลข้างเคียงจะเรียกว่าไม่มีวงเล็บ "

จากบล็อกโพสต์Scala Syntax Primer :

"คำจำกัดความของโพรซีเดอร์คือนิยามของฟังก์ชันที่ไม่ระบุประเภทผลลัพธ์และเครื่องหมายเท่ากับนิพจน์ที่กำหนดต้องเป็นบล็อกเช่น def f (ps) {stats} เทียบเท่ากับ def f (ps): Unit = {stats }.

ตัวอย่างที่ 4.6.3 นี่คือการประกาศและ de? nition ของโพรซีเดอร์ที่ชื่อว่า write:

trait Writer {
    def write(str: String)
}
object Terminal extends Writer {
    def write(str: String) { System.out.println(str) }
}

รหัสด้านบนจะเสร็จสมบูรณ์โดยปริยายของรหัสต่อไปนี้:

trait Writer {
    def write(str: String): Unit
}
object Terminal extends Writer {
    def write(str: String): Unit = { System.out.println(str) }
}"

จากข้อกำหนดภาษา:

"ด้วยวิธีการที่ใช้พารามิเตอร์เดียว Scala อนุญาตให้นักพัฒนาแทนที่. ด้วยช่องว่างและละเว้นวงเล็บเปิดใช้ไวยากรณ์ตัวดำเนินการที่แสดงในตัวอย่างตัวดำเนินการแทรกของเราไวยากรณ์นี้ใช้ในที่อื่น ๆ ใน Scala API เช่น เป็นการสร้างอินสแตนซ์ช่วง:

val firstTen:Range = 0 to 9

ที่นี่อีกครั้งถึง (Int) เป็นวิธีการวานิลลาที่ประกาศภายในคลาส (จริงๆแล้วมีการแปลงประเภทโดยนัยมากกว่าที่นี่ แต่คุณจะได้รับการล่องลอย) "

จากScala for Java Refugees ตอนที่ 6: การข้าม Java :

"ตอนนี้เมื่อคุณลอง" m 0 "Scala จะทิ้งมันไปเนื่องจากเป็นตัวดำเนินการแบบยูนารีเนื่องจากไม่ใช่ตัวดำเนินการที่ถูกต้อง (~,!, - และ +) พบว่า" m "เป็นวัตถุที่ถูกต้อง - มันเป็นฟังก์ชันไม่ใช่วิธีการและฟังก์ชันทั้งหมดเป็นวัตถุ

เนื่องจาก "0" ไม่ใช่ตัวระบุ Scala ที่ถูกต้องจึงไม่สามารถเป็นได้ทั้ง infix หรือตัวดำเนินการ postfix ดังนั้นสกาล่าบ่นว่าคาด ";" - ซึ่งจะแยกนิพจน์ที่ถูกต้อง (เกือบ) สองนิพจน์: "m" และ "0" ถ้าคุณใส่มันก็จะบ่นว่า m ต้องการอาร์กิวเมนต์หรือไม่ก็ให้ "_" เปลี่ยนเป็นฟังก์ชันที่ใช้บางส่วน "

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

ฉันสามารถละอักขระใดใน Scala ได้

แต่สิ่งที่ทำให้ฉันสับสนก็คือคำพูดนี้:

"จำเป็นต้องมีวัตถุเพื่อรับการเรียกใช้เมธอดตัวอย่างเช่นคุณไม่สามารถทำ“ println“ Hello World!” ได้เนื่องจาก println ต้องการผู้รับวัตถุ คุณสามารถทำ“ Console println“ Hello World!”” ที่ตอบสนองความต้องการได้”

เพราะเท่าที่ผมสามารถดูมีเป็นวัตถุที่จะรับสาย ...


1
โอเคลองอ่านแหล่งข้อมูลจำเพาะเพื่อรับเบาะแสและว้าว นี่เป็นตัวอย่างที่ดีของปัญหาเกี่ยวกับรหัสเวทย์มนตร์ - มิกซ์อินมากเกินไปประเภทการอนุมานและการแปลงโดยนัยและพารามิเตอร์โดยนัย มันยากที่จะเข้าใจจากภายนอกใน! สำหรับห้องสมุดขนาดใหญ่เช่นนั้นการใช้เครื่องมือที่ดีกว่าอาจทำสิ่งมหัศจรรย์ ... วันหนึ่ง ...
Antony Stubbs

3

ฉันคิดว่ามันง่ายกว่าที่จะทำตามกฎง่ายๆนี้: ในช่องว่างของนิพจน์จะสลับกันระหว่างวิธีการและพารามิเตอร์ ในตัวอย่างของแยกวิเคราะห์เป็น(service.findAllPresentations.get.first.votes.size) must be equalTo(2) (service.findAllPresentations.get.first.votes.size).must(be)(equalTo(2))โปรดสังเกตว่าวงเล็บรอบ 2 มีความสัมพันธ์สูงกว่าช่องว่าง จุดยังมีการเชื่อมโยงกันสูงขึ้นเพื่อจะแยกเป็น(service.findAllPresentations.get.first.votes.size) must be.equalTo(2)(service.findAllPresentations.get.first.votes.size).must(be.equalTo(2))

service findAllPresentations get first votes size must be equalTo 2แยกวิเคราะห์เป็นservice.findAllPresentations(get).first(votes).size(must).be(equalTo).2.


2

จริงๆแล้วในการอ่านครั้งที่สองนี่อาจเป็นกุญแจสำคัญ:

ด้วยวิธีการที่ใช้พารามิเตอร์เดียว Scala อนุญาตให้ผู้พัฒนาแทนที่ไฟล์. ด้วยการเว้นวรรคและละเว้นวงเล็บ

ตามที่ระบุไว้ในบล็อกโพสต์: http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-6

ดังนั้นบางทีนี่อาจเป็น "syntax sugar" ที่เข้มงวดมากซึ่งใช้ได้เฉพาะในกรณีที่คุณเรียก methodอย่างมีประสิทธิภาพบน object ซึ่งใช้พารามิเตอร์เดียว เช่น

1 + 2
1.+(2)

และไม่มีอะไรอื่น

นี่จะอธิบายตัวอย่างของฉันในคำถาม

แต่อย่างที่บอกถ้ามีคนชี้ให้เห็นว่าตรงไหนในสเป็คภาษาที่ระบุไว้จะได้รับการชื่นชมมาก

โอเคเพื่อนที่ดี (paulp_ จาก #scala) ได้ชี้ให้เห็นว่าข้อมูลนี้อยู่ที่ใดในข้อมูลจำเพาะของภาษา:

6.12.3: ลำดับความสำคัญและความสัมพันธ์ของตัวดำเนินการกำหนดการจัดกลุ่มส่วนต่างๆของนิพจน์ดังนี้

  • หากมีการดำเนินการ infix หลายรายการในนิพจน์ตัวดำเนินการที่มีลำดับความสำคัญสูงกว่าจะผูกติดกันมากกว่าตัวดำเนินการที่มีลำดับความสำคัญต่ำกว่า
  • หากมีการดำเนินการ infix ติดต่อกัน e0 op1 e1 op2 . .opn en กับโอเปอเรเตอร์ op1,. . . , opn ที่มีลำดับความสำคัญเดียวกันดังนั้นตัวดำเนินการทั้งหมดเหล่านี้จะต้องมีการเชื่อมโยงเดียวกัน ถ้าตัวดำเนินการทั้งหมดเชื่อมโยงกันทางซ้ายลำดับจะถูกตีความเป็น (.. (e0 op1 e1) op2..) opn en มิฉะนั้นถ้าตัวดำเนินการทั้งหมดถูกต้องเหมาะสมลำดับจะถูกตีความเป็น e0 op1 (e1 op2 (. .opn en).)
  • ตัวดำเนินการ Postfix มีลำดับความสำคัญต่ำกว่าตัวดำเนินการ infix เสมอ เช่น e1 op1 e2 op2 จะเทียบเท่ากับ (e1 op1 e2) op2 เสมอ

ตัวถูกดำเนินการด้านขวาของตัวดำเนินการเชื่อมโยงด้านซ้ายอาจประกอบด้วยอาร์กิวเมนต์หลายตัวที่อยู่ในวงเล็บเช่น e op (e1,.., en) จากนั้นนิพจน์นี้จะถูกตีความเป็น e.op (e1,.., en)

การดำเนินการไบนารีที่เชื่อมโยงด้านซ้าย e1 op e2 ถูกตีความเป็น e1.op (e2) ถ้า op เป็น rightassociative การดำเนินการเดียวกันจะถูกตีความว่า {val x = e1; e2.op (x)} โดยที่ x เป็นชื่อใหม่

อืม - สำหรับฉันมันไม่ตรงกับสิ่งที่ฉันเห็นหรือฉันแค่ไม่เข้าใจ;)


อืมเพื่อเพิ่มความสับสนนี่ก็ใช้ได้เช่นกัน: ((((((realService findAllPresentations) get) โหวตก่อน) ขนาด) ต้องเท่ากันถึง 2 แต่ไม่ใช่ถ้าฉันลบคู่วงเล็บเหล่านั้นออก ...
Antony Stubbs

2

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

คำแนะนำนี้เป็นความพยายามที่ระบบเอฟเฟกต์เป็นหลักที่ล้มเหลว (เพื่อไม่ให้สับสนกับ: มีประโยชน์น้อยกว่าระบบเอฟเฟกต์อื่น ๆ )

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


แต่นั่นเป็นปัญหาเมื่อคุณทำงานกับภาษา OO / Functional แบบไฮบริดใช่ไหม ในตัวอย่างที่ใช้งานได้จริงคุณจะต้องการมีฟังก์ชันผลข้างเคียง ... คุณช่วยชี้ให้เราทราบข้อมูลเกี่ยวกับ "ระบบเอฟเฟกต์" ได้หรือไม่? ฉันคิดว่ายิ่งมีเครื่องหมายอ้างอิงมากเท่าไหร่ก็คือ "ฟังก์ชันที่ไม่มีพารามิเตอร์สามารถประกาศได้โดยไม่มีวงเล็บซึ่งในกรณีนี้จะต้องถูกเรียกโดยไม่มีวงเล็บสิ่งนี้ให้การสนับสนุนสำหรับ Uniform Access Principle ดังนั้นผู้เรียกจะไม่ทราบว่า สัญลักษณ์คือตัวแปรหรือฟังก์ชันที่ไม่มีพารามิเตอร์ ".
Antony Stubbs
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.