อะไรคือความแตกต่างระหว่างคลาสเคสของสกาล่ากับคลาส?


440

ฉันค้นหาใน Google เพื่อค้นหาความแตกต่างระหว่างที่และcase class classทุกคนกล่าวว่าเมื่อคุณต้องการจับคู่รูปแบบในคลาสให้ใช้คลาสเคส มิฉะนั้นใช้คลาสและยังกล่าวถึงสิทธิพิเศษบางอย่างเช่นเท่ากับและรหัสแฮชแทนที่ แต่เหตุผลเหล่านี้เป็นเหตุผลเดียวที่ควรใช้คลาสเคสแทนคลาส?

ฉันเดาว่าควรมีเหตุผลที่สำคัญมากสำหรับคุณลักษณะนี้ใน Scala คำอธิบายหรือมีแหล่งข้อมูลเพื่อเรียนรู้เพิ่มเติมเกี่ยวกับคลาสเคสสคาลาคืออะไร?

คำตอบ:


394

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

แนวคิดการทำงานนี้ช่วยให้เราสามารถ

  • ใช้ไวยากรณ์เริ่มต้นกะทัดรัด ( Node(1, Leaf(2), None)))
  • ย่อยสลายพวกเขาโดยใช้การจับคู่รูปแบบ
  • มีการเปรียบเทียบความเท่าเทียมกันโดยนัยที่กำหนดไว้

ร่วมกับมรดกเรียนกรณีที่จะใช้ในการเลียนแบบประเภทข้อมูลเกี่ยวกับพีชคณิต

หากวัตถุทำการคำนวณแบบ stateful ภายในหรือแสดงพฤติกรรมที่ซับซ้อนชนิดอื่น ๆ มันควรจะเป็นชั้นสามัญ


11
@Teja: อย่างใด ADT นั้นเป็นพารามิเตอร์แบบ kinda มีประสิทธิภาพสูงและเป็นประเภทที่ปลอดภัย
Dario

8
คลาสตัวพิมพ์ปิดผนึกใช้เพื่อเลียนแบบข้อมูลพีชคณิต มิฉะนั้นจำนวนคลาสย่อยจะไม่ถูก จำกัด
Thomas Jung

6
@Thomas: พูดอย่างถูกต้อง, การเรียนกรณีที่เกิดจากการเรียนนามธรรมปิดผนึกเลียนแบบประเภทข้อมูลเกี่ยวกับพีชคณิตปิดขณะ ADT เป็นอย่างอื่นเปิด
Dario

2
@Dario ... และชนิดนั้นเปิดอยู่มิฉะนั้นจะเป็น ADT :-)
โทมัสจอง

1
@Thomas: ใช่มันเป็นเพียงอัตถิภาวนิยม;)
Dario

165

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

ตัวอย่างง่ายๆของประเภทนี้คือต้นไม้ เช่นต้นไม้ไบนารีสามารถดำเนินการเช่นนี้:

sealed abstract class Tree
case class Node(left: Tree, right: Tree) extends Tree
case class Leaf[A](value: A) extends Tree
case object EmptyLeaf extends Tree

ที่ทำให้เราสามารถทำสิ่งต่อไปนี้:

// DSL-like assignment:
val treeA = Node(EmptyLeaf, Leaf(5))
val treeB = Node(Node(Leaf(2), Leaf(3)), Leaf(5))

// On Scala 2.8, modification through cloning:
val treeC = treeA.copy(left = treeB.left)

// Pretty printing:
println("Tree A: "+treeA)
println("Tree B: "+treeB)
println("Tree C: "+treeC)

// Comparison:
println("Tree A == Tree B: %s" format (treeA == treeB).toString)
println("Tree B == Tree C: %s" format (treeB == treeC).toString)

// Pattern matching:
treeA match {
  case Node(EmptyLeaf, right) => println("Can be reduced to "+right)
  case Node(left, EmptyLeaf) => println("Can be reduced to "+left)
  case _ => println(treeA+" cannot be reduced")
}

// Pattern matches can be safely done, because the compiler warns about
// non-exaustive matches:
def checkTree(t: Tree) = t match {
  case Node(EmptyLeaf, Node(left, right)) =>
  // case Node(EmptyLeaf, Leaf(el)) =>
  case Node(Node(left, right), EmptyLeaf) =>
  case Node(Leaf(el), EmptyLeaf) =>
  case Node(Node(l1, r1), Node(l2, r2)) =>
  case Node(Leaf(e1), Leaf(e2)) =>
  case Node(Node(left, right), Leaf(el)) =>
  case Node(Leaf(el), Node(left, right)) =>
  // case Node(EmptyLeaf, EmptyLeaf) =>
  case Leaf(el) =>
  case EmptyLeaf =>
}

โปรดทราบว่าต้นไม้สร้างและแยกโครงสร้าง (ผ่านการจับคู่รูปแบบ) ด้วยไวยากรณ์เดียวกันซึ่งเป็นวิธีการพิมพ์อย่างแน่นอน (ลบด้วยการเว้นวรรค)

และยังสามารถใช้กับแผนที่แฮชหรือชุดเนื่องจากมีแฮชโค้ดที่ถูกต้องและเสถียร


71
  • คลาสเคสสามารถจับคู่รูปแบบได้
  • คลาสเคสจะกำหนดแฮชโค้ดและเท่ากับโดยอัตโนมัติ
  • คลาส Case จะกำหนดเมธอด getter โดยอัตโนมัติสำหรับอาร์กิวเมนต์ตัวสร้าง

(คุณได้กล่าวถึงทั้งหมดยกเว้นอันสุดท้าย)

นั่นเป็นข้อแตกต่างของคลาสปกติเท่านั้น


13
Setters ไม่ถูกสร้างขึ้นสำหรับคลาสเคสยกเว้นว่าระบุ "var" ในอาร์กิวเมนต์ตัวสร้างซึ่งในกรณีนี้คุณจะได้รับการสร้าง getter / setter เช่นเดียวกับคลาสปกติ
Mitch Blevins

1
@ Mitch: จริงฉันไม่ดี แก้ไขแล้ว
sepp2k

คุณละ 2 ข้อแตกต่างดูคำตอบของฉัน
Shelby Moore III

@MitchBlevins คลาสปกติไม่จำเป็นต้องสร้าง getter / setter เสมอไป
Shelby Moore III

คลาสเคสกำหนดเมธอดที่ใช้อย่างไม่มีเหตุผลนั่นคือเหตุผลที่พวกเขาสามารถจับคู่รูปแบบ
Happy Torturer

30

ไม่มีใครพูดถึงว่าคลาสเคสเป็นอินสแตนซ์ของProductและทำให้สืบทอดเมธอดเหล่านี้:

def productElement(n: Int): Any
def productArity: Int
def productIterator: Iterator[Any]

โดยที่productArityคืนค่าจำนวนพารามิเตอร์คลาสproductElement(i)ส่งคืนพารามิเตอร์i thและproductIteratorอนุญาตให้วนซ้ำได้


2
อย่างไรก็ตามมันไม่ใช่อินสแตนซ์ของ Product1, Product2 เป็นต้น
Jean-Philippe Pellet

27

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

หมายเหตุคุณสามารถแทนที่ค่าเริ่มต้นได้ด้วยการต่อท้ายอาร์กิวเมนต์ตัวสร้างแต่ละตัวด้วยvarสำหรับคลาสเคส อย่างไรก็ตามการทำให้คลาสเคสไม่แน่นอนทำให้equalsและhashCodeวิธีการเป็นตัวแปรเวลา [1]

sepp2kได้กล่าวถึงแล้วว่าคลาสเคสสร้างequalsและhashCodeวิธีการโดยอัตโนมัติ

ไม่มีใครพูดถึงว่าคลาสเคสจะสร้างคู่หูที่objectมีชื่อเดียวกันกับคลาสซึ่งมีapplyและunapplyวิธีการโดยอัตโนมัติ applyวิธีการช่วยให้การสร้างอินสแตนซ์โดยไม่ต้อง prepending newกับ unapplyวิธีการระบายช่วยให้จับคู่รูปแบบที่คนพูดถึง

นอกจากนี้คอมไพเลอร์เพิ่มประสิทธิภาพความเร็วของการmatch- caseจับคู่รูปแบบสำหรับการเรียนกรณี [2]

[1] คลาสของเคสนั้นเจ๋งมาก

[2] กรณีคลาสและสกัด PG 15


12

การสร้างคลาสเคสใน Scala ยังถูกมองว่าเป็นความสะดวกในการลบแผ่นบาง ๆ

เมื่อสร้างคลาสเคส Scala ให้คุณดังต่อไปนี้

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

เนื่องจากคลาสไม่มีการเปลี่ยนแปลงคุณจะได้รับ accessors ซึ่งเป็นเพียงตัวแปร (หรือคุณสมบัติ) ของคลาส แต่ไม่มีการเปลี่ยนแปลง (ดังนั้นจึงไม่สามารถเปลี่ยนตัวแปรได้) พารามิเตอร์ Constructor พร้อมให้คุณใช้งานโดยอัตโนมัติในฐานะฟิลด์อ่านอย่างเดียวแบบสาธารณะ ใช้งานได้ดีกว่าการสร้าง Java bean

  • นอกจากนี้คุณยังจะได้รับhashCode, equalsและtoStringวิธีการโดยค่าเริ่มต้นและequalsวิธีการเปรียบเทียบวัตถุก่อสร้าง copyวิธีการที่ถูกสร้างขึ้นเพื่อให้สามารถโคลนวัตถุ (มีบางสาขาที่มีค่าใหม่ให้กับวิธีการ)

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


ในสาระสำคัญสิ่งที่คุณได้รับจาก Scala เมื่อสร้างคลาสเคส (หรืออ็อบเจ็กต์เคสหากคลาสของคุณไม่มีอาร์กิวเมนต์) เป็นวัตถุซิงเกิลตันซึ่งทำหน้าที่เป็นโรงงานและเป็นตัวแยกไฟล์


ทำไมคุณต้องการสำเนาของวัตถุที่ไม่เปลี่ยนรูป?
Paŭlo Ebermann

@ PaŭloEbermannเพราะcopyวิธีการที่สามารถปรับเปลี่ยนสาขา:val x = y.copy(foo="newValue")
Thilo

8

นอกเหนือจากสิ่งที่ผู้คนพูดไปแล้วมีความแตกต่างพื้นฐานระหว่างclassและcase class

1. Case Classไม่ต้องการชัดเจนnewในขณะที่ต้องเรียกคลาสด้วยnew

val classInst = new MyClass(...)  // For classes
val classInst = MyClass(..)       // For case class

2. พารามิเตอร์คอนสตรัคเตอร์เริ่มต้นเป็นแบบส่วนตัวในclassขณะที่เป็นสาธารณะcase class

// For class
class MyClass(x:Int) { }
val classInst = new MyClass(10)

classInst.x   // FAILURE : can't access

// For caseClass
case class MyClass(x:Int) { }
val classInst = MyClass(10)

classInst.x   // SUCCESS

3. case classเปรียบเทียบตนเองตามมูลค่า

// case Class
class MyClass(x:Int) { }

val classInst = new MyClass(10)
val classInst2 = new MyClass(10)

classInst == classInst2 // FALSE

// For Case Class
case class MyClass(x:Int) { }

val classInst = MyClass(10)
val classInst2 = MyClass(10)

classInst == classInst2 // TRUE

6

ตามเอกสารของ Scala :

คลาส Case เป็นเพียงคลาสปกติที่:

  • ไม่เปลี่ยนเป็นค่าเริ่มต้น
  • Decomposable ผ่านการจับคู่รูปแบบ
  • เปรียบเทียบโดยความเท่าเทียมกันของโครงสร้างแทนการอ้างอิง
  • รวบรัดเพื่อยกตัวอย่างและใช้งาน

คุณสมบัติอีกอย่างของคีย์เวิร์ดcaseคือคอมไพเลอร์สร้างวิธีการต่าง ๆ ให้เราโดยอัตโนมัติรวมถึงเมธอด toString, equals และ hashCode ที่คุ้นเคยใน Java


5

ประเภท:

scala> class Animal(name:String)
defined class Animal

scala> val an1 = new Animal("Padddington")
an1: Animal = Animal@748860cc

scala> an1.name
<console>:14: error: value name is not a member of Animal
       an1.name
           ^

แต่ถ้าเราใช้รหัสเดียวกัน แต่ใช้คลาสกรณี:

scala> case class Animal(name:String)
defined class Animal

scala> val an2 = new Animal("Paddington")
an2: Animal = Animal(Paddington)

scala> an2.name
res12: String = Paddington


scala> an2 == Animal("fred")
res14: Boolean = false

scala> an2 == Animal("Paddington")
res15: Boolean = true

ระดับบุคคล:

scala> case class Person(first:String,last:String,age:Int)
defined class Person

scala> val harry = new Person("Harry","Potter",30)
harry: Person = Person(Harry,Potter,30)

scala> harry
res16: Person = Person(Harry,Potter,30)
scala> harry.first = "Saily"
<console>:14: error: reassignment to val
       harry.first = "Saily"
                   ^
scala>val saily =  harry.copy(first="Saily")
res17: Person = Person(Saily,Potter,30)

scala> harry.copy(age = harry.age+1)
res18: Person = Person(Harry,Potter,31)

การจับคู่รูปแบบ:

scala> harry match {
     | case Person("Harry",_,age) => println(age)
     | case _ => println("no match")
     | }
30

scala> res17 match {
     | case Person("Harry",_,age) => println(age)
     | case _ => println("no match")
     | }
no match

วัตถุ: ซิงเกิล:

scala> case class Person(first :String,last:String,age:Int)
defined class Person

scala> object Fred extends Person("Fred","Jones",22)
defined object Fred

5

ในการมีความเข้าใจที่ดีที่สุดของคลาสคลาสคืออะไร:

สมมติว่านิยามคลาสเคสต่อไปนี้:

case class Foo(foo:String, bar: Int)

จากนั้นทำสิ่งต่อไปนี้ในเทอร์มินัล:

$ scalac -print src/main/scala/Foo.scala

สกาล่า 2.12.8 จะส่งออก:

...
case class Foo extends Object with Product with Serializable {

  <caseaccessor> <paramaccessor> private[this] val foo: String = _;

  <stable> <caseaccessor> <accessor> <paramaccessor> def foo(): String = Foo.this.foo;

  <caseaccessor> <paramaccessor> private[this] val bar: Int = _;

  <stable> <caseaccessor> <accessor> <paramaccessor> def bar(): Int = Foo.this.bar;

  <synthetic> def copy(foo: String, bar: Int): Foo = new Foo(foo, bar);

  <synthetic> def copy$default$1(): String = Foo.this.foo();

  <synthetic> def copy$default$2(): Int = Foo.this.bar();

  override <synthetic> def productPrefix(): String = "Foo";

  <synthetic> def productArity(): Int = 2;

  <synthetic> def productElement(x$1: Int): Object = {
    case <synthetic> val x1: Int = x$1;
        (x1: Int) match {
            case 0 => Foo.this.foo()
            case 1 => scala.Int.box(Foo.this.bar())
            case _ => throw new IndexOutOfBoundsException(scala.Int.box(x$1).toString())
        }
  };

  override <synthetic> def productIterator(): Iterator = scala.runtime.ScalaRunTime.typedProductIterator(Foo.this);

  <synthetic> def canEqual(x$1: Object): Boolean = x$1.$isInstanceOf[Foo]();

  override <synthetic> def hashCode(): Int = {
     <synthetic> var acc: Int = -889275714;
     acc = scala.runtime.Statics.mix(acc, scala.runtime.Statics.anyHash(Foo.this.foo()));
     acc = scala.runtime.Statics.mix(acc, Foo.this.bar());
     scala.runtime.Statics.finalizeHash(acc, 2)
  };

  override <synthetic> def toString(): String = scala.runtime.ScalaRunTime._toString(Foo.this);

  override <synthetic> def equals(x$1: Object): Boolean = Foo.this.eq(x$1).||({
      case <synthetic> val x1: Object = x$1;
        case5(){
          if (x1.$isInstanceOf[Foo]())
            matchEnd4(true)
          else
            case6()
        };
        case6(){
          matchEnd4(false)
        };
        matchEnd4(x: Boolean){
          x
        }
    }.&&({
      <synthetic> val Foo$1: Foo = x$1.$asInstanceOf[Foo]();
      Foo.this.foo().==(Foo$1.foo()).&&(Foo.this.bar().==(Foo$1.bar())).&&(Foo$1.canEqual(Foo.this))
  }));

  def <init>(foo: String, bar: Int): Foo = {
    Foo.this.foo = foo;
    Foo.this.bar = bar;
    Foo.super.<init>();
    Foo.super./*Product*/$init$();
    ()
  }
};

<synthetic> object Foo extends scala.runtime.AbstractFunction2 with Serializable {

  final override <synthetic> def toString(): String = "Foo";

  case <synthetic> def apply(foo: String, bar: Int): Foo = new Foo(foo, bar);

  case <synthetic> def unapply(x$0: Foo): Option =
     if (x$0.==(null))
        scala.None
     else
        new Some(new Tuple2(x$0.foo(), scala.Int.box(x$0.bar())));

  <synthetic> private def readResolve(): Object = Foo;

  case <synthetic> <bridge> <artifact> def apply(v1: Object, v2: Object): Object = Foo.this.apply(v1.$asInstanceOf[String](), scala.Int.unbox(v2));

  def <init>(): Foo.type = {
    Foo.super.<init>();
    ()
  }
}
...

ในขณะที่เราสามารถดูคอมไพเลอร์สกาล่าผลิตคลาสปกติFooและวัตถุFooร่วม

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

  • สถานะภายในของFooคลาสเปลี่ยนรูป:
val foo: String
val bar: Int
  • getters:
def foo(): String
def bar(): Int
  • วิธีการคัดลอก:
def copy(foo: String, bar: Int): Foo
def copy$default$1(): String
def copy$default$2(): Int
  • การใช้scala.Productลักษณะ:
override def productPrefix(): String
def productArity(): Int
def productElement(x$1: Int): Object
override def productIterator(): Iterator
  • การใช้scala.Equalsคุณลักษณะสำหรับทำอินสแตนซ์ของคลาสเคสเทียบเคียงได้กับความเท่าเทียมกันโดย==:
def canEqual(x$1: Object): Boolean
override def equals(x$1: Object): Boolean
  • เอาชนะjava.lang.Object.hashCodeการปฏิบัติตามสัญญาเท่ากับ -hashcode:
override <synthetic> def hashCode(): Int
  • การเอาชนะjava.lang.Object.toString:
override def toString(): String
  • คอนสตรัคสำหรับการสร้างตัวอย่างโดยnewคำหลัก:
def <init>(foo: String, bar: Int): Foo 

Object Foo: - วิธีการapplyสร้างอินสแตนซ์โดยไม่มีnewคีย์เวิร์ด:

case <synthetic> def apply(foo: String, bar: Int): Foo = new Foo(foo, bar);
  • วิธีการแยกunupplyสำหรับการใช้คลาส case foo ในการจับคู่รูปแบบ:
case <synthetic> def unapply(x$0: Foo): Option
  • วิธีการในการปกป้องวัตถุในรูปแบบซิงเกิลจากการดีซีเรียลไลเซชันสำหรับการไม่ปล่อยให้ผลิตอีกหนึ่งอินสแตนซ์:
<synthetic> private def readResolve(): Object = Foo;
  • วัตถุ Foo ขยายscala.runtime.AbstractFunction2การทำเคล็ดลับดังกล่าว:
scala> case class Foo(foo:String, bar: Int)
defined class Foo

scala> Foo.tupled
res1: ((String, Int)) => Foo = scala.Function2$$Lambda$224/1935637221@9ab310b

tupled จาก object ส่งคืน funtion เพื่อสร้าง Foo ใหม่โดยใช้ tuple 2 องค์ประกอบ

ดังนั้นคลาสเคสจึงเป็นเพียงวากยสัมพันธ์


4

ไม่เหมือนกับคลาสคลาสเคสจะถูกใช้เพื่อเก็บข้อมูล

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

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


3

ไม่มีใครพูดถึงว่าวัตถุร่วมชั้นกรณีมีการtupledป้องกันซึ่งมีประเภท:

case class Person(name: String, age: Int)
//Person.tupled is def tupled: ((String, Int)) => Person

กรณีใช้งานเดียวที่ฉันหาได้คือเมื่อคุณต้องการสร้างคลาสเคสจาก tuple ตัวอย่าง:

val bobAsTuple = ("bob", 14)
val bob = (Person.apply _).tupled(bobAsTuple) //bob: Person = Person(bob,14)

คุณสามารถทำสิ่งเดียวกันโดยไม่ต้องมี tupled โดยสร้างวัตถุโดยตรง แต่ถ้าชุดข้อมูลของคุณแสดงเป็นรายการของ tuple ที่มี arity 20 (tuple ที่มี 20 องค์ประกอบ) อาจใช้ tupled เป็นตัวเลือกของคุณ


3

ระดับกรณีที่เป็นชั้นที่อาจจะนำมาใช้กับที่match/caseคำสั่ง

def isIdentityFun(term: Term): Boolean = term match {
  case Fun(x, Var(y)) if x == y => true
  case _ => false
}

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

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

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

สิ่งที่เรียนกรณีที่มีความไม่เป็นประโยชน์หรือไม่? วัตถุบางอย่างมีสถานะรหัสเช่นconnection.setConnectTimeout(connectTimeout)นั้นไม่ได้มีไว้สำหรับคลาสกรณี

และตอนนี้คุณสามารถอ่านA Tour of Scala: Case Classes


2

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

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

นักพัฒนาบางคนหลีกเลี่ยงการเขียนคลาสเคสเนื่องจาก 20 เมธอดเพิ่มเติมซึ่งคุณสามารถดูได้โดยการแยกส่วนไฟล์คลาส

กรุณาดูที่ลิงค์นี้ถ้าคุณต้องการที่จะตรวจสอบวิธีการทั้งหมดที่อยู่ภายในชั้นกรณี


1
  • คลาส Case กำหนดอ็อบเจกต์ compagnon ด้วยวิธีการประยุกต์และไม่ใช้
  • คลาสเคสขยายได้ Serializable
  • คลาสเคสกำหนดเมธอด hashCode และการคัดลอก
  • คุณลักษณะทั้งหมดของนวกรรมิกคือ val (น้ำตาลประโยค)

1

คุณสมบัติที่สำคัญบางประการของcase classesรายการด้านล่าง

  1. คลาสเคสไม่เปลี่ยนรูป
  2. คุณสามารถสร้างอินสแตนซ์ของคลาสเคสโดยไม่มีnewคำหลัก
  3. คลาสเคสสามารถเปรียบเทียบโดยค่า

ตัวอย่างโค้ดสกาล่าบนซอสกาล่านำมาจากเอกสารสกาล่า

https://scalafiddle.io/sf/34XEQyE/0

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