ความแตกต่างระหว่างวิธีการและฟังก์ชั่นใน Scala


254

ฉันอ่านฟังก์ชั่นสกาล่า (เป็นส่วนหนึ่งของทัวร์สกาล่าอีกครั้ง ) ในโพสต์ที่เขาระบุว่า:

วิธีการและฟังก์ชั่นไม่เหมือนกัน

แต่เขาไม่ได้อธิบายอะไรเกี่ยวกับมัน เขากำลังพยายามจะพูดอะไร



3
ฉันคิดว่าคุณสามารถได้รับบางสิ่งจากความแตกต่างระหว่างวิธีและฟังก์ชั่นคืออะไร
jinglining

คำถามติดตามผลพร้อมคำตอบที่ดี: ฟังก์ชัน vs เมธอดใน Scala
Josiah Yoder

คำตอบ:


238

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

ก่อนอื่นเรามาดูกันว่าสเปคของสกาล่าบอกอะไรเราบ้าง บทที่ 3 (ประเภท) บอกเราเกี่ยวกับประเภทฟังก์ชั่น (3.2.9) และประเภทวิธี (3.3.1) บทที่ 4 (การประกาศพื้นฐาน) พูดถึงการประกาศมูลค่าและคำจำกัดความ (4.1) การประกาศตัวแปรและคำจำกัดความ (4.2) และการประกาศฟังก์ชั่นและคำจำกัดความ (4.6) บทที่ 6 (การแสดงออก) พูดถึงฟังก์ชั่นที่ไม่ระบุชื่อ (6.23) และค่าวิธีการ (6.7) อยากรู้อยากเห็นค่าฟังก์ชั่นจะพูดครั้งเดียวใน 3.2.9 และไม่มีที่ไหนอีก

ประเภทฟังก์ชั่นคือ (ประมาณ) ประเภทของรูปแบบ(T1, ... , TN) => Uซึ่งเป็นชวเลขสำหรับลักษณะที่FunctionNอยู่ในห้องสมุดมาตรฐาน ฟังก์ชั่นที่ไม่ระบุชื่อและค่าวิธีการมีประเภทฟังก์ชั่นและประเภทฟังก์ชั่นสามารถนำมาใช้เป็นส่วนหนึ่งของค่าการประกาศตัวแปรและฟังก์ชั่นและคำจำกัดความ ในความเป็นจริงมันสามารถเป็นส่วนหนึ่งของชนิดวิธี

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

ราคาประกาศและคำนิยามและการประกาศตัวแปรและนิยามอยู่valและvarประกาศรวมทั้งชนิดและความคุ้มค่า - ซึ่งจะเป็นไปตามลำดับประเภทฟังก์ชั่นและไม่เปิดเผยตัวฟังก์ชั่นหรือค่าวิธี โปรดทราบว่าใน JVM ค่าเหล่านี้ (ค่าวิธีการ) จะถูกนำไปใช้กับสิ่งที่ Java เรียกว่า "วิธีการ"

ประกาศฟังก์ชั่น คือdefการประกาศรวมทั้งชนิดและร่างกาย ส่วนประเภทคือประเภทวิธีและร่างกายเป็นแสดงออกหรือบล็อก สิ่งนี้ถูกนำไปใช้กับ JVM ด้วยสิ่งที่ Java เรียกว่า "เมธอด"

ในที่สุดฟังก์ชั่นที่ไม่ระบุชื่อเป็นตัวอย่างของฟังก์ชั่นประเภท (เช่นอินสแตนซ์ของลักษณะFunctionN) และค่าวิธีการเป็นสิ่งเดียวกัน! ความแตกต่างคือว่าค่าวิธีการที่ถูกสร้างขึ้นจากวิธีการอย่างใดอย่างหนึ่งโดยการ postfixing ขีดล่าง ( m _เป็นค่าวิธีการที่สอดคล้องกับ "ประกาศฟังก์ชั่น" ( def) m) หรือโดยกระบวนการที่เรียกว่าการขยายตัว etaซึ่งเป็นเหมือน ฟังก์ชั่น

นั่นคือสิ่งที่สเป็คพูดดังนั้นขอผมพูดแบบนี้เถอะ: เราไม่ใช้คำศัพท์นั้น! มันนำไปสู่ความสับสนมากเกินไประหว่างสิ่งที่เรียกว่า"การประกาศฟังก์ชั่น"ซึ่งเป็นส่วนหนึ่งของโปรแกรม (บทที่ 4 - การประกาศพื้นฐาน) และ"ฟังก์ชั่นที่ไม่ระบุชื่อ"ซึ่งเป็นนิพจน์และ"ประเภทฟังก์ชั่น"ซึ่งก็คือ ทั้งประเภท - ลักษณะ

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

ดังนั้นเมื่อมีการเปลี่ยนแปลงคำศัพท์ข้างต้นนี่เป็นคำอธิบายที่ใช้งานได้จริงของความแตกต่าง

ฟังก์ชั่นเป็นวัตถุที่มีหนึ่งที่FunctionXมีลักษณะเช่นFunction0, Function1, Function2ฯลฯ มันอาจจะรวมถึงเช่นกันซึ่งจริงขยายPartialFunctionFunction1

ลองดูประเภทลายเซ็นของหนึ่งในคุณสมบัติเหล่านี้:

trait Function2[-T1, -T2, +R] extends AnyRef

ลักษณะนี้มีวิธีนามธรรม (มีวิธีที่เป็นรูปธรรมเช่นกัน):

def apply(v1: T1, v2: T2): R

และนั่นบอกพวกเราทุกคนว่าต้องรู้อะไรเกี่ยวกับมัน ฟังก์ชั่นมีapplyวิธีการที่ได้รับไม่มีค่าพารามิเตอร์ของประเภทT1 , T2 , ... , เทนเนสซีRและบางสิ่งบางอย่างจากประเภทผลตอบแทน มันเป็นตัวแปรที่ตรงกันข้ามกับพารามิเตอร์ที่ได้รับและตัวแปรร่วมกับผลลัพธ์

ที่แปรปรวนหมายความว่าเป็นชนิดย่อยของFunction1[Seq[T], String] Function1[List[T], AnyRef]การเป็นประเภทย่อยหมายถึงมันสามารถใช้แทนมันได้ หนึ่งสามารถเห็นได้อย่างง่ายดายว่าถ้าฉันจะโทรf(List(1, 2, 3))และคาดว่าจะAnyRefกลับมาทั้งสองประเภทข้างต้นจะทำงาน

ทีนี้ความคล้ายคลึงกันของเมธอดและฟังก์ชั่นคืออะไร? ทีนี้ถ้าfเป็นฟังก์ชั่นและmเป็นวิธีการภายในขอบเขตแล้วทั้งสองสามารถเรียกเช่นนี้:

val o1 = f(List(1, 2, 3))
val o2 = m(List(1, 2, 3))

การเรียกเหล่านี้จะแตกต่างกันจริง ๆ เพราะสิ่งแรกคือน้ำตาลแบบวากยสัมพันธ์ สกาล่าขยายไปที่:

val o1 = f.apply(List(1, 2, 3))

fซึ่งแน่นอนเป็นวิธีการเรียกบนวัตถุ ฟังก์ชั่นยังมีน้ำตาลในประโยคอื่น ๆ เพื่อประโยชน์ของมัน: ตัวอักษรฟังก์ชั่น (สองของพวกเขาจริง) และ(T1, T2) => Rลายเซ็นประเภท ตัวอย่างเช่น:

val f = (l: List[Int]) => l mkString ""
val g: (AnyVal) => String = {
  case i: Int => "Int"
  case d: Double => "Double"
  case o => "Other"
}

ความคล้ายคลึงกันระหว่างเมธอดและฟังก์ชั่นก็คือความสามารถในอดีตที่สามารถแปลงเป็นหลัง:

val f = m _

Scala จะขยายตัวที่สมมติว่าmชนิด(List[Int])AnyRefเข้า (Scala 2.7):

val f = new AnyRef with Function1[List[Int], AnyRef] {
  def apply(x$1: List[Int]) = this.m(x$1)
}

บน Scala 2.8 มันใช้AbstractFunction1คลาสเพื่อลดขนาดคลาส

โปรดสังเกตว่าไม่มีวิธีแปลงวิธีอื่น ๆ - จากฟังก์ชันเป็นวิธี

อย่างไรก็ตามวิธีการมีข้อได้เปรียบที่ยิ่งใหญ่อย่างหนึ่ง (ดีสอง - พวกเขาสามารถเร็วกว่าเล็กน้อย): พวกเขาสามารถรับพารามิเตอร์ประเภทได้ ตัวอย่างเช่นในขณะที่fข้างต้นจำเป็นต้องระบุประเภทของListมันได้รับ ( List[Int]ในตัวอย่าง) mสามารถ parameterize มัน:

def m[T](l: List[T]): String = l mkString ""

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


26
คำอธิบายนี้ชัดเจนมาก ทำได้ดี. น่าเสียดายที่ทั้ง Odersky / Venners / Spoon book และ Scala spec ใช้คำว่า "function" และ "method" แทนกันบ้าง (พวกเขาน่าจะพูดได้ว่า "function" โดยที่ "method" จะชัดเจนกว่า แต่บางครั้งมันก็เกิดขึ้นในทางกลับกันเช่นในส่วนที่ 6.7 ของ spec ซึ่งครอบคลุมการแปลงวิธีการทำงานเป็นชื่อ "Method Values" .) ฉันคิดว่าการใช้คำเหล่านี้อย่างหลวม ๆ ทำให้เกิดความสับสนมากมายเมื่อผู้คนพยายามเรียนรู้ภาษา
Seth Tisue

4
@Seth ฉันรู้ฉันรู้ - PinS เป็นหนังสือที่สอนให้ฉันสกาล่า ฉันเรียนรู้วิธีที่ดีกว่าเช่นพอลพอลตั้งฉันให้ตรง
Daniel C. Sobral

4
คำอธิบายที่ดี! ฉันมีสิ่งหนึ่งที่จะเพิ่ม: เมื่อคุณอ้างถึงการขยายตัวของval f = mคอมไพเลอร์ตามที่val f = new AnyRef with Function1[List[Int], AnyRef] { def apply(x$1: List[Int]) = this.m(x$1) }คุณควรชี้ให้เห็นว่าวิธีthisการภายในapplyไม่ได้อ้างอิงถึงAnyRefวัตถุ แต่ไปยังวัตถุที่มีการval f = m _ประเมินวิธีการ( ด้านนอก thisเพื่อที่จะพูด ) เนื่องจากthisเป็นค่าที่ถูกปิดโดยการปิด (เช่นเช่นreturnตามที่ระบุไว้ด้านล่าง)
Holger Peine

1
@ DanielC.Sobral หนังสือพินที่คุณพูดถึงคืออะไร? ฉันสนใจเรียนรู้สกาล่าด้วยและไม่พบหนังสือที่มีชื่อนั้น
tldr

5
@tldr การเขียนโปรแกรมใน Scalaโดย Odersky และอื่น ๆ มันเป็นตัวย่อที่ใช้กันทั่วไป (พวกเขาบอกฉันว่าพวกเขาไม่ชอบ PiS ด้วยเหตุผลบางอย่าง!)
Daniel C. Sobral

67

ความแตกต่างในทางปฏิบัติที่สำคัญอย่างหนึ่งระหว่างเมธอดและฟังก์ชันคือความreturnหมาย returnผลตอบแทนที่ได้จากวิธีการเดียวเท่านั้น ตัวอย่างเช่น:

scala> val f = () => { return "test" }
<console>:4: error: return outside method definition
       val f = () => { return "test" }
                       ^

กลับมาจากฟังก์ชั่นที่กำหนดไว้ในวิธีการที่จะส่งกลับไม่ใช่ท้องถิ่น:

scala> def f: String = {                 
     |    val g = () => { return "test" }
     | g()                               
     | "not this"
     | }
f: String

scala> f
res4: String = test

ในขณะที่ส่งคืนจากเมธอดโลคัลส่งคืนจากเมธอดนั้นเท่านั้น

scala> def f2: String = {         
     | def g(): String = { return "test" }
     | g()
     | "is this"
     | }
f2: String

scala> f2
res5: String = is this

9
นั่นเป็นเพราะผลตอบแทนถูกจับโดยการปิด
Daniel C. Sobral

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

2
@ รูต - สิ่งที่เกี่ยวกับการกลับมาจากภายในfor (a <- List(1, 2, 3)) { return ... }? ที่ได้รับ de-sugared เพื่อปิด
Ben Lings

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

1
สุจริตฉันจะใช้ไวยากรณ์ที่แตกต่าง ได้returnคืนค่าจากฟังก์ชั่นและบางรูปแบบescapeหรือbreakหรือcontinueเพื่อกลับจากวิธีการ
Ryan The Leach

38

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

การเขียนโปรแกรมใน Scala Second Edition Martin Odersky - Lex Spoon - Bill Venners


1
ฟังก์ชั่นสามารถอยู่ในชั้นเรียนเป็น def หรือเป็น val / var เฉพาะ def ของเป็นวิธีการ
Josiah Yoder

29

สมมติว่าคุณมีรายการ

scala> val x =List.range(10,20)
x: List[Int] = List(10, 11, 12, 13, 14, 15, 16, 17, 18, 19)

กำหนดวิธีการ

scala> def m1(i:Int)=i+2
m1: (i: Int)Int

กำหนดฟังก์ชั่น

scala> (i:Int)=>i+2
res0: Int => Int = <function1>

scala> x.map((x)=>x+2)
res2: List[Int] = List(12, 13, 14, 15, 16, 17, 18, 19, 20, 21)

วิธีการรับอาร์กิวเมนต์

scala> m1(2)
res3: Int = 4

กำหนดฟังก์ชั่นด้วยวาล

scala> val p =(i:Int)=>i+2
p: Int => Int = <function1>

อาร์กิวเมนต์ฟังก์ชั่นเป็นตัวเลือก

 scala> p(2)
    res4: Int = 4

scala> p
res5: Int => Int = <function1>

อาร์กิวเมนต์ของเมธอดคือข้อบังคับ

scala> m1
<console>:9: error: missing arguments for method m1;
follow this method with `_' if you want to treat it as a partially applied function

ตรวจสอบบทช่วยสอนต่อไปนี้ที่อธิบายถึงการส่งผ่านความแตกต่างอื่น ๆ ด้วยตัวอย่างเช่นตัวอย่างอื่นของ diff กับฟังก์ชั่น Method Vs, การใช้ฟังก์ชั่นเป็น Variables, การสร้างฟังก์ชันที่ส่งคืนฟังก์ชัน


13

ฟังก์ชั่นไม่รองรับค่าเริ่มต้นของพารามิเตอร์ วิธีการทำ การแปลงจากเมธอดไปยังฟังก์ชันจะสูญเสียค่าดีฟอลต์ของพารามิเตอร์ (สกาล่า 2.8.1)


5
มีเหตุผลนี้หรือไม่
corazza

7

มีบทความที่ดีที่นี่ซึ่งคำอธิบายของฉันส่วนใหญ่ถูกนำมา เปรียบเทียบฟังก์ชั่นและวิธีการสั้น ๆ เกี่ยวกับความเข้าใจของฉัน หวังว่าจะช่วย:

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

val f1 = (x: Int) => x + x
f1(2)  // 4

บรรทัดข้างต้นไม่มีอะไรยกเว้นการกำหนดวัตถุหนึ่งให้กับอีกวัตถุหนึ่งเช่น object1 = object2 อันที่จริง object2 ในตัวอย่างของเราคือฟังก์ชันที่ไม่ระบุตัวตนและด้านซ้ายได้รับชนิดของวัตถุเนื่องจากสิ่งนั้น ดังนั้นตอนนี้ f1 เป็นวัตถุ (ฟังก์ชั่น) ฟังก์ชั่นที่ไม่ระบุชื่อเป็นจริงตัวอย่างของ Function1 [Int, Int] ที่หมายถึงฟังก์ชั่นที่มี 1 พารามิเตอร์ประเภท int และค่าตอบแทนประเภท int การเรียก f1 โดยไม่มีข้อโต้แย้งจะทำให้เรามีลายเซ็นของฟังก์ชันที่ไม่ระบุตัวตน (Int => Int =)

วิธีการ : พวกมันไม่ใช่วัตถุ แต่ถูกกำหนดให้กับอินสแตนซ์ของคลาสเช่นวัตถุ เหมือนกับวิธีการในฟังก์ชั่น java หรือสมาชิกใน c ++ (ตามที่Raffi Khatchadourianชี้ให้เห็นในการแสดงความคิดเห็นต่อคำถามนี้ ) และอื่น ๆ ตัวอย่างง่ายๆของวิธีนี้ก็เหมือนกับการร้อง:

def m1(x: Int) = x + x
m1(2)  // 4

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

val f2 = m1 _  // Int => Int = <function1>

การ "กำหนดวิธีให้กับฟังก์ชั่น" หมายความว่าอย่างไร มันหมายความว่าตอนนี้คุณมีวัตถุที่มีพฤติกรรมแบบเดียวกับที่ใช้หรือไม่?
K. M

@KM: val f2 = m1 _ เทียบเท่ากับ val f2 = new Function1 [Int, Int] {def m1 (x: Int) = x + x};
สึเกะ

3

นี่คือโพสต์ที่ยอดเยี่ยมโดย Rob Norris ซึ่งอธิบายความแตกต่างนี่คือ TL; DR

เมธอดใน Scala ไม่ใช่ค่า แต่เป็นฟังก์ชั่น คุณสามารถสร้างฟังก์ชั่นที่มอบหมายให้วิธีการผ่านการขยายตัว ((เรียกโดยสิ่งที่ต่อท้ายขีดเส้นใต้)

ด้วยคำจำกัดความต่อไปนี้:

วิธีเป็นสิ่งที่กำหนดไว้กับdefและคุ้มค่าเป็นสิ่งที่คุณสามารถกำหนดให้กับVal

สรุป ( แยกจากบล็อก ):

valเมื่อเรากำหนดวิธีการที่เราจะเห็นว่าเราไม่สามารถกำหนดให้

scala> def add1(n: Int): Int = n + 1
add1: (n: Int)Int

scala> val f = add1
<console>:8: error: missing arguments for method add1;
follow this method with `_' if you want to treat it as a partially applied function
       val f = add1

โปรดทราบประเภทของadd1ซึ่งไม่ดูปกติ (n: Int)Intคุณไม่สามารถประกาศตัวแปรของชนิด วิธีการไม่ใช่ค่า

อย่างไรก็ตามโดยการเพิ่มตัวดำเนินการ postfix (- ขยาย (pron เด่นชัดคือ "eta") เราสามารถเปลี่ยนวิธีการเป็นค่าฟังก์ชัน หมายเหตุ: fประเภทของ

scala> val f = add1 _
f: Int => Int = <function1>

scala> f(3)
res0: Int = 4

ผลกระทบของ_คือการดำเนินการเทียบเท่าต่อไปนี้: เราสร้างFunction1อินสแตนซ์ที่มอบหมายให้วิธีการของเรา

scala> val g = new Function1[Int, Int] { def apply(n: Int): Int = add1(n) }
g: Int => Int = <function1>

scala> g(3)
res18: Int = 4

1

ใน Scala 2.13 ซึ่งแตกต่างจากฟังก์ชั่นวิธีการสามารถรับ / คืน

  • พารามิเตอร์ประเภท (วิธี polymorphic)
  • พารามิเตอร์โดยนัย
  • ประเภทขึ้นอยู่กับ

อย่างไรก็ตามข้อ จำกัด เหล่านี้จะยกเป็นจุด (Scala 3) โดยฟังก์ชันประเภท Polymorphic # 4672ตัวอย่างเช่นรุ่น dotty 0.23.0-RC1เปิดใช้งานไวยากรณ์ต่อไปนี้

พิมพ์พารามิเตอร์

def fmet[T](x: List[T]) = x.map(e => (e, e))
val ffun = [T] => (x: List[T]) => x.map(e => (e, e))

พารามิเตอร์โดยนัย ( พารามิเตอร์บริบท )

def gmet[T](implicit num: Numeric[T]): T = num.zero
val gfun: [T] => Numeric[T] ?=> T = [T] => (using num: Numeric[T]) => num.zero

ประเภทขึ้นอยู่กับ

class A { class B }
def hmet(a: A): a.B = new a.B
val hfun: (a: A) => a.B = hmet

สำหรับตัวอย่างเพิ่มเติมดูการทดสอบ / run / polymorphic-functions.scala


0

ในทางปฏิบัติโปรแกรมเมอร์ของ Scala ต้องการเพียงรู้กฎสามข้อต่อไปนี้เพื่อใช้ฟังก์ชั่นและวิธีการอย่างถูกต้อง:

  • วิธีการที่กำหนดโดยdefและตัวอักษรฟังก์ชั่นที่กำหนดโดย=>เป็นฟังก์ชั่น มันถูกกำหนดไว้ในหน้า 143 บทที่ 8 ในหนังสือ Programming ใน Scala ฉบับที่ 4
  • ค่าฟังก์ชั่นเป็นวัตถุที่สามารถส่งผ่านเป็นค่าใด ๆ ตัวอักษรฟังก์ชั่นและฟังก์ชั่นการใช้งานบางส่วนเป็นค่าฟังก์ชั่น
  • คุณสามารถทิ้งขีดเส้นใต้ของฟังก์ชันที่นำไปใช้บางส่วนได้หากต้องการค่าฟังก์ชันที่จุดหนึ่งในรหัส ตัวอย่างเช่น:someNumber.foreach(println)

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

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