อะไรคือความแตกต่างอย่างเป็นทางการใน Scala ระหว่างวงเล็บปีกกาและวงเล็บและควรใช้เมื่อใด?


329

เป็นความแตกต่างอย่างเป็นทางการระหว่างการขัดแย้งผ่านฟังก์ชั่นในวงเล็บอะไร()และในการจัดฟัน{}?

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

ตัวอย่างเช่น (หมายถึงเพียงตัวอย่างฉันจะขอบคุณคำตอบใด ๆ ที่กล่าวถึงกรณีทั่วไปไม่ใช่เฉพาะตัวอย่างนี้เท่านั้น):

val tupleList = List[(String, String)]()
val filtered = tupleList.takeWhile( case (s1, s2) => s1 == s2 )

=> ข้อผิดพลาด: การเริ่มต้นของการแสดงออกอย่างง่ายที่ผิดกฎหมาย

val filtered = tupleList.takeWhile{ case (s1, s2) => s1 == s2 }

=> สบายดี

คำตอบ:


365

ฉันพยายามเขียนเกี่ยวกับสิ่งนี้ แต่ฉันก็ยอมแพ้ในที่สุดเนื่องจากกฎกติกาค่อนข้างกระจายออกไป โดยทั่วไปคุณจะต้องได้รับการแขวนของมัน

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

List(1, 2, 3).reduceLeft{_ + _} // valid, single Function2[Int,Int] parameter

List{1, 2, 3}.reduceLeft(_ + _) // invalid, A* vararg parameter

อย่างไรก็ตามคุณจำเป็นต้องรู้เพื่อให้เข้าใจกฎเหล่านี้ได้ดีขึ้น

เพิ่มการตรวจสอบคอมไพล์ด้วย parens

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

method {
  1 +
  2
  3
}

method(
  1 +
  2
  3
)

error: ')' expected but integer literal foundคอมไพล์ครั้งแรกที่สองให้ ผู้เขียนต้องการเขียน1 + 2 + 3ผู้เขียนอยากจะเขียน

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

การใช้คำฟุ่มเฟื่อย

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

... วงเล็บปีกกาปิดอยู่บนบรรทัดของตัวเองทันทีหลังจากบรรทัดสุดท้ายของฟังก์ชัน

การจัดรูปแบบอัตโนมัติจำนวนมากเช่นเดียวกับใน IntelliJ จะทำการฟอร์แมตใหม่โดยอัตโนมัติสำหรับคุณ ดังนั้นพยายามที่จะใช้ parens รอบเมื่อคุณสามารถ

สัญกรณ์ผูก

เมื่อใช้สัญกรณ์ infix เช่นList(1,2,3) indexOf (2)คุณสามารถละเว้นวงเล็บถ้ามีเพียงหนึ่งพารามิเตอร์และเขียนเป็นList(1, 2, 3) indexOf 2คุณสามารถละเว้นวงเล็บถ้ามีเพียงหนึ่งพารามิเตอร์และเขียนเป็นนี่ไม่ใช่กรณีของเครื่องหมายจุด

โปรดทราบว่าเมื่อคุณมีพารามิเตอร์เดียวที่เป็นนิพจน์แบบหลายโทเค็นเช่นx + 2หรือa => a % 2 == 0คุณต้องใช้วงเล็บเพื่อระบุขอบเขตของการแสดงออก

tuples

เพราะคุณสามารถละเว้นวงเล็บบางครั้งบางครั้ง tuple ต้องการวงเล็บพิเศษเช่นใน และบางครั้งวงเล็บด้านนอกสามารถละเว้นเหมือนใน((1, 2)) (1, 2)นี่อาจทำให้เกิดความสับสน

ฟังก์ชั่น / ตัวอักษรฟังก์ชั่นบางส่วนด้วย case

Scala มีไวยากรณ์สำหรับฟังก์ชันและฟังก์ชันตัวอักษรบางส่วน ดูเหมือนว่านี้:

{
    case pattern if guard => statements
    case pattern => statements
}

สถานที่อื่น ๆ ที่คุณสามารถใช้caseคำสั่งได้คือกับmatchและcatchคำหลัก:

object match {
    case pattern if guard => statements
    case pattern => statements
}
try {
    block
} catch {
    case pattern if guard => statements
    case pattern => statements
} finally {
    block
}

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

นิพจน์และบล็อก

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

{
    import stuff._
    statement ; // ; optional at the end of the line
    statement ; statement // not optional here
    var x = 0 // declaration
    while (x < 10) { x += 1 } // stuff
    (x % 5) + 1 // expression
}

( expression )

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

( { var x = 0; while (x < 10) { x += 1}; x } % 5) + 1

ดังนั้นเนื่องจากการแสดงออกเป็นงบและบล็อกของรหัสเป็นนิพจน์ทุกอย่างด้านล่างนี้ถูกต้อง:

1       // literal
(1)     // expression
{1}     // block of code
({1})   // expression with a block of code
{(1)}   // block of code with an expression
({(1)}) // you get the drift...

พวกเขาจะไม่สามารถใช้แทนกันได้

โดยทั่วไปคุณไม่สามารถแทนที่{}ด้วย()หรือกลับกันได้ทุกที่ ตัวอย่างเช่น:

while (x < 10) { x += 1 }

นี่ไม่ใช่การเรียกใช้เมธอดดังนั้นคุณจึงไม่สามารถเขียนด้วยวิธีอื่นได้ คุณสามารถใส่วงเล็บปีกกาไว้ในวงเล็บสำหรับconditionหรือใช้วงเล็บในวงเล็บปีกกาสำหรับบล็อกของรหัส:

while ({x < 10}) { (x += 1) }

ดังนั้นฉันหวังว่านี่จะช่วยได้


53
นี่คือสาเหตุที่ผู้คนโต้แย้งว่าสกาล่านั้นซับซ้อน ฉันจะเรียกตัวเองว่าเป็นคนที่กระตือรือร้นสกาล่า
andyczerwonka

ไม่ต้องแนะนำขอบเขตสำหรับทุกวิธีที่ฉันคิดว่าทำให้รหัส Scala ง่ายขึ้น! เป็นการดีที่ไม่ควรใช้วิธีการ{}- ทุกอย่างควรจะเป็นการแสดงออกที่บริสุทธิ์
samthebest

1
@ andyczerwonka ฉันเห็นด้วยอย่างสิ้นเชิง แต่มันเป็นราคาที่เป็นธรรมชาติและหลีกเลี่ยงไม่ได้ (?) คุณจ่ายเพื่อความยืดหยุ่นและพลังในการแสดงออก => สกาล่าไม่เกินราคา นี่เป็นตัวเลือกที่เหมาะสมสำหรับสถานการณ์เฉพาะใด ๆ ซึ่งแน่นอนว่าเป็นอีกเรื่องหนึ่ง
ษคานข Nazary

สวัสดีเมื่อคุณพูดว่าList{1, 2, 3}.reduceLeft(_ + _)ไม่ถูกต้องคุณหมายถึงว่ามีไวยากรณ์ผิดพลาดหรือไม่ แต่ฉันพบว่ารหัสสามารถรวบรวมได้ ฉันใส่รหัสของฉันที่นี่
calvin

ที่คุณใช้ในตัวอย่างทั้งหมดแทนList(1, 2, 3) List{1, 2, 3}อนิจจาในรุ่นปัจจุบันของ Scala (2.13) สิ่งนี้ล้มเหลวด้วยข้อความแสดงข้อผิดพลาดที่แตกต่างกัน (จุลภาคที่ไม่คาดคิด) คุณต้องกลับไปที่ 2.7 หรือ 2.8 เพื่อรับข้อผิดพลาดเดิมอาจเป็นไปได้
Daniel C. Sobral

56

มีคู่ของกฎระเบียบที่แตกต่างกันและหาข้อสรุปที่เกิดขึ้นที่นี่เป็นครั้งแรกของทุกอนุมาน Scala วงเล็บเมื่อพารามิเตอร์เป็นฟังก์ชั่นเช่นในการจัดฟันจะสรุปมันเป็นเพียงรูปแบบสั้นlist.map(_ * 2) list.map({_ * 2})ประการที่สอง Scala อนุญาตให้คุณข้ามวงเล็บในรายการพารามิเตอร์สุดท้ายหากรายการพารามิเตอร์นั้นมีหนึ่งพารามิเตอร์และเป็นฟังก์ชั่นดังนั้นจึงlist.foldLeft(0)(_ + _)สามารถเขียนเป็นlist.foldLeft(0) { _ + _ }(หรือlist.foldLeft(0)({_ + _})ถ้าคุณต้องการให้ชัดเจนเป็นพิเศษ)

อย่างไรก็ตามถ้าคุณเพิ่มcaseคุณจะได้รับตามที่คนอื่นพูดถึงฟังก์ชั่นบางส่วนแทนฟังก์ชั่นและ Scala จะไม่อนุมานวงเล็บปีกกาสำหรับฟังก์ชั่นบางส่วนดังนั้นlist.map(case x => x * 2)จะไม่ทำงาน แต่ทั้งสองlist.map({case x => 2 * 2})และlist.map { case x => x * 2 }จะ


4
ไม่เพียง แต่ในรายการพารามิเตอร์สุดท้าย ตัวอย่างเช่นการlist.foldLeft{0}{_+_}ทำงาน
Daniel C. Sobral

1
อาฉันแน่ใจว่าฉันได้อ่านว่ามันเป็นเพียงรายการพารามิเตอร์สุดท้าย แต่ชัดเจนว่าฉันผิด! ดีแล้วที่รู้.
Theo

23

มีความพยายามจากชุมชนในการสร้างมาตรฐานการใช้วงเล็บปีกกาและวงเล็บให้ดูที่คู่มือสไตล์สกาล่า (หน้า 21): http://www.codecommit.com/scala-style-guide.pdf

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

val filtered = tupleList takeWhile { case (s1, s2) => s1 == s2 }

สำหรับการโทร metod "ปกติ" คุณควรใช้จุดและวงเล็บ

val result = myInstance.foo(5, "Hello")

18
จริงๆแล้วการประชุมคือการใช้วงเล็บปีกกาลิงค์ที่ไม่เป็นทางการ นี่เป็นเพราะในการเขียนโปรแกรมฟังก์ชั่นฟังก์ชั่นทั้งหมดเป็นเพียงพลเมืองลำดับแรกและดังนั้นจึงไม่ควรได้รับการปฏิบัติที่แตกต่างกัน ประการที่สองมาร์ตินโอเดอร์ สกี ว่าคุณควรพยายามที่จะใช้เฉพาะมัดสำหรับผู้ประกอบเช่นวิธีการ (เช่น+, --) takeWhileวิธีการไม่ปกติเช่น จุดสัญกรณ์ทั้งหมดของ infix คือการอนุญาตให้ใช้ DSL และผู้ประกอบการที่กำหนดเองดังนั้นจึงควรใช้มันในบริบทนี้ไม่ใช่ตลอดเวลา
samthebest

17

ฉันไม่คิดว่าจะมีอะไรพิเศษหรือซับซ้อนเกี่ยวกับการดัดผมหยิกในสกาล่า ในการควบคุมการใช้งานที่ซับซ้อนที่ดูเหมือนของพวกเขาใน Scala เพียงจำสิ่งที่อยู่ในใจสองอย่าง:

  1. เครื่องหมายปีกกาแบบหยิกเป็นบล็อกของโค้ดซึ่งประเมินเป็นบรรทัดสุดท้ายของโค้ด (เกือบทุกภาษาทำสิ่งนี้)
  2. ฟังก์ชั่นหากต้องการสามารถสร้างขึ้นด้วยบล็อกของรหัส (ตามกฎ 1)
  3. วงเล็บปีกกาสามารถละเว้นรหัสหนึ่งบรรทัดข้อยกเว้นสำหรับกรณี (Scala เลือก)
  4. สามารถละเว้นวงเล็บในการเรียกใช้ฟังก์ชันด้วยการบล็อกรหัสเป็นพารามิเตอร์ (ตัวเลือก Scala)

เรามาอธิบายตัวอย่างต่อกฎสามข้อข้างต้น:

val tupleList = List[(String, String)]()
// doesn't compile, violates case clause requirement
val filtered = tupleList.takeWhile( case (s1, s2) => s1 == s2 ) 
// block of code as a partial function and parentheses omission,
// i.e. tupleList.takeWhile({ case (s1, s2) => s1 == s2 })
val filtered = tupleList.takeWhile{ case (s1, s2) => s1 == s2 }

// curly braces omission, i.e. List(1, 2, 3).reduceLeft({_+_})
List(1, 2, 3).reduceLeft(_+_)
// parentheses omission, i.e. List(1, 2, 3).reduceLeft({_+_})
List(1, 2, 3).reduceLeft{_+_}
// not both though it compiles, because meaning totally changes due to precedence
List(1, 2, 3).reduceLeft _+_ // res1: String => String = <function1>

// curly braces omission, i.e. List(1, 2, 3).foldLeft(0)({_ + _})
List(1, 2, 3).foldLeft(0)(_ + _)
// parentheses omission, i.e. List(1, 2, 3).foldLeft(0)({_ + _})
List(1, 2, 3).foldLeft(0){_ + _}
// block of code and parentheses omission
List(1, 2, 3).foldLeft {0} {_ + _}
// not both though it compiles, because meaning totally changes due to precedence
List(1, 2, 3).foldLeft(0) _ + _
// error: ';' expected but integer literal found.
List(1, 2, 3).foldLeft 0 (_ + _)

def foo(f: Int => Unit) = { println("Entering foo"); f(4) }
// block of code that just evaluates to a value of a function, and parentheses omission
// i.e. foo({ println("Hey"); x => println(x) })
foo { println("Hey"); x => println(x) }

// parentheses omission, i.e. f({x})
def f(x: Int): Int = f {x}
// error: missing arguments for method f
def f(x: Int): Int = f x

1. ไม่จริงในทุกภาษา 4. ไม่เป็นความจริงใน Scala เช่น: def f (x: Int) = fx
aij

@aij ขอบคุณสำหรับความคิดเห็น สำหรับ 1 ฉันได้แนะนำความเป็นอยู่ที่สกาลาให้กับ{}พฤติกรรม ฉันได้อัปเดตข้อความเพื่อความแม่นยำแล้ว และสำหรับ 4 มันค่อนข้างยุ่งยากเล็กน้อยเนื่องจากการมีปฏิสัมพันธ์ระหว่าง()และ{}เป็นdef f(x: Int): Int = f {x}ผลงานและนั่นคือสาเหตุที่ฉันได้อันดับที่ 5 :)
LCN

1
ฉันมักจะคิดว่า () และ {} เป็นส่วนใหญ่ที่ใช้แทนกันได้ใน Scala ยกเว้นว่าจะแยกวิเคราะห์เนื้อหาที่แตกต่างกัน ปกติฉันไม่ได้เขียน f ({x}) ดังนั้น f {x} จึงไม่รู้สึกเหมือนกับว่าไม่ละวงเล็บเลยเท่ากับแทนที่มันด้วย curlies ภาษาอื่น ๆ จะอนุญาตให้คุณละเว้น paretheses ตัวอย่างเช่นfun f(x) = f xมีผลใน SML
aij

@aij การปฏิบัติf {x}เช่นf({x})นี้ดูเหมือนจะเป็นคำอธิบายที่ดีกว่าสำหรับฉันเนื่องจากความคิด()และการ{}ใช้แทนกันนั้นใช้งานได้ง่ายกว่า โดยวิธีการf({x})ตีความได้รับการสนับสนุนค่อนข้างโดยสเป็คสกาล่า (มาตรา 6.6):ArgumentExprs ::= ‘(’ [Exprs] ‘)’ | ‘(’ [Exprs ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ’)’ | [nl] BlockExp
lcn

13

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

การที่เราสามารถทำสิ่งต่าง ๆ เช่น:

2 + { 3 }             // res: Int = 5
val x = { 4 }         // res: x: Int = 4
List({1},{2},{3})     // res: List[Int] = List(1,2,3)

ตัวอย่างสุดท้ายเป็นเพียงการเรียกใช้ฟังก์ชันที่มีพารามิเตอร์สามตัวซึ่งแต่ละพารามิเตอร์จะถูกประเมินก่อน

ทีนี้มาดูกันว่ามันทำงานอย่างไรกับการเรียกใช้ฟังก์ชั่นลองนิยามฟังก์ชั่นง่าย ๆ ที่ใช้ฟังก์ชั่นอื่นเป็นพารามิเตอร์

def foo(f: Int => Unit) = { println("Entering foo"); f(4) }

ในการเรียกใช้เราจำเป็นต้องส่งผ่านฟังก์ชั่นที่ใช้พารามิเตอร์ Int หนึ่งประเภทดังนั้นเราจึงสามารถใช้ฟังก์ชันสัญพจน์และส่งผ่านไปยัง foo ได้:

foo( x => println(x) )

ทีนี้อย่างที่ได้กล่าวไปแล้วก่อนที่เราจะสามารถใช้บล็อคโค้ดแทนนิพจน์ได้ดังนั้นให้ใช้มัน

foo({ x => println(x) })

สิ่งที่เกิดขึ้นที่นี่คือโค้ดภายใน {} ได้รับการประเมินและค่าฟังก์ชันจะถูกส่งคืนเป็นค่าของการประเมินผลบล็อกจากนั้นค่านี้จะถูกส่งผ่านไปยัง foo นี่คือความหมายเหมือนกับการโทรก่อนหน้า

แต่เราสามารถเพิ่มบางอย่างเพิ่มเติมได้ที่:

foo({ println("Hey"); x => println(x) })

ตอนนี้บล็อคโค้ดของเรามีสองข้อความ, และเนื่องจากมันถูกประเมินก่อนที่จะทำการเรียกใช้งาน foo, สิ่งที่เกิดขึ้นคือพิมพ์ครั้งแรก "เฮ้", จากนั้นฟังก์ชั่นของเราถูกส่งไปยัง foo, "Entering foo" ถูกพิมพ์และสุดท้าย .

มันดูค่อนข้างน่าเกลียดและ Scala ช่วยให้เราสามารถข้ามวงเล็บในกรณีนี้เพื่อให้เราสามารถเขียน:

foo { println("Hey"); x => println(x) }

หรือ

foo { x => println(x) }

ที่ดูดีกว่ามากและเทียบเท่ากับอดีต ที่นี่ยังมีการประเมินบล็อคของโค้ดก่อนและผลลัพธ์ของการประเมิน (ซึ่งคือ x => println (x)) จะถูกส่งผ่านเป็นอาร์กิวเมนต์เพื่อ foo


1
เป็นแค่ฉันเท่านั้น แต่ฉันชอบความชัดเจนของธรรมชาติfoo({ x => println(x) })มากกว่า บางทีผมติดเกินไปในรูปแบบของฉัน ...
เดด

7

เนื่องจากคุณกำลังใช้caseงานคุณกำลังกำหนดฟังก์ชันบางส่วนและฟังก์ชันบางส่วนจำเป็นต้องใช้เครื่องหมายปีกกา


1
ฉันขอคำตอบโดยทั่วไปไม่ใช่แค่คำตอบสำหรับตัวอย่างนี้
Marc-François

5

เพิ่มการตรวจสอบคอมไพล์ด้วย parens

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

method {
  1 +
  2
  3
}

method(
  1 +
  2
  3
 )

คอมไพล์แรกที่สองให้error: ')' expected but integer literal found.ผู้เขียนต้องการเขียน1 + 2 + 3ผู้เขียนอยากจะเขียน

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

การใช้คำฟุ่มเฟื่อย

บันทึกย่อที่สำคัญที่มักถูกมองข้ามเกี่ยวกับการใช้คำฟุ่มเฟื่อย การใช้วงเล็บปีกกาอย่างหลีกเลี่ยงไม่ได้นำไปสู่รหัส verbose เนื่องจากคู่มือสไตล์สกาล่าอย่างชัดเจนระบุว่าวงเล็บปีกกาปิดต้องอยู่ในบรรทัดของตัวเอง: http://docs.scala-lang.org/style/declarations.html "... วงเล็บปีกกาปิด อยู่ในบรรทัดของตัวเองทันทีหลังจากบรรทัดสุดท้ายของฟังก์ชัน " การจัดรูปแบบอัตโนมัติจำนวนมากเช่นใน Intellij จะทำการฟอร์แมตใหม่โดยอัตโนมัติสำหรับคุณ ดังนั้นพยายามที่จะใช้ parens รอบเมื่อคุณสามารถ เช่นList(1, 2, 3).reduceLeft{_ + _}กลายเป็น:

List(1, 2, 3).reduceLeft {
  _ + _
}

-2

ด้วยเครื่องมือจัดฟันคุณจะได้เครื่องหมายอัฒภาคสำหรับคุณและวงเล็บไม่ใช่ พิจารณาtakeWhileฟังก์ชั่นเนื่องจากมันคาดว่าฟังก์ชั่นบางส่วนเพียง{case xxx => ??? }ความหมายที่ถูกต้องแทนวงเล็บรอบการแสดงออกกรณี

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