[scala] 스칼라의 사례 클래스와 클래스의 차이점은 무엇입니까?

a case class와 a 의 차이점을 찾기 위해 Google을 검색했습니다 class. 모든 사람들은 클래스에서 패턴 일치를 원할 때 유스 케이스 클래스를 언급합니다. 그렇지 않으면 클래스를 사용하고 equals 및 hash 코드 재정의와 같은 추가 특권을 언급하십시오. 그러나 이것이 클래스 대신 케이스 클래스를 사용해야하는 유일한 이유입니까?

스칼라에는이 기능에 대한 몇 가지 중요한 이유가 있다고 생각합니다. 스칼라 사례 클래스에 대한 설명은 무엇입니까?



답변

케이스 클래스는 생성자 인수에만 의존하는 단순하고 변경 불가능한 데이터 보유 오브젝트 로 볼 수 있습니다 .

이 기능 개념을 통해

  • 간단한 초기화 구문 사용 ( Node(1, Leaf(2), None)))
  • 패턴 일치를 사용하여 분해
  • 암시 적으로 정의 된 동등 비교

상속과 함께 case 클래스는 대수 데이터 유형 을 모방하는 데 사용됩니다 .

객체가 내부에서 상태 저장 계산을 수행하거나 다른 종류의 복잡한 동작을 나타내는 경우 일반 클래스 여야합니다.


답변

기술적으로 클래스와 케이스 클래스에는 차이가 없습니다. 컴파일러가 케이스 클래스를 사용할 때 일부 내용을 최적화하더라도 마찬가지입니다. 그러나 사례 클래스는 대수 데이터 유형을 구현하는 특정 패턴에 대한 보일러 플레이트를 제거하는 데 사용됩니다 .

이러한 유형의 매우 간단한 예는 나무입니다. 예를 들어 이진 트리는 다음과 같이 구현할 수 있습니다.

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 =>
}

트리는 동일한 구문을 사용하여 패턴 일치를 통해 구성 및 해체합니다. 이는 동일한 방식으로 인쇄되는 방법입니다 (마이너스 공백).

또한 유효하고 안정적인 hashCode를 가지고 있기 때문에 해시 맵 또는 세트와 함께 사용할 수도 있습니다.


답변

  • 케이스 클래스는 패턴 일치 가능
  • 케이스 클래스는 자동으로 해시 코드를 정의하고
  • 케이스 클래스는 생성자 인수에 대한 getter 메소드를 자동으로 정의합니다.

(당신은 이미 마지막 것을 제외한 모든 것을 언급했습니다).

이것들은 정규 수업과의 유일한 차이점입니다.


답변

사례 클래스도 인스턴스 Product이므로이 메소드를 상속 한다고 언급 한 사람은 없습니다 .

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

여기서, productArity클래스 매개 변수 수를 productElement(i)리턴하고 i 번째 매개 변수를 리턴하며 해당 매개 변수를 productIterator반복 할 수 있습니다.


답변

케이스 클래스에 val생성자 매개 변수 가 있다고 언급 한 사람은 없지만 일반 클래스의 기본값이기도합니다 ( 스칼라 디자인에 불일치라고 생각합니다 ). 다리 오는 ” 불변 ” 이라고 언급 한 곳을 암시했다 .

var케이스 클래스에 대해 각 생성자 인수를 앞에 추가하여 기본값을 대체 할 수 있습니다 . 그러나 케이스 클래스를 변경 가능하게하면 메소드 equalshashCode메소드가 시간 변형됩니다. [1]

sepp2k는 이미 사례 클래스가 자동으로 생성 equals되고 hashCode메소드가 있다고 언급했습니다 .

또한 아무도 경우 클래스가 자동으로 동반자를 만드는 것이 언급되지 object들어있는 클래스와 같은 이름을 가진 applyunapply방법. 이 apply방법을 사용하면 앞에 추가하지 않고 인스턴스를 생성 할 수 있습니다 new. unapply추출 방법은 다른 언급하는 패턴 매칭을 가능하게한다.

또한 컴파일러는 속도를 최적화합니다 matchcase 케이스 클래스 패턴 매칭 [2]가.

[1] 케이스 클래스는 멋지다

[2] 사례 분류 및 추출기, pg 15 .


답변

Scala의 케이스 클래스 구성은 보일러 플레이트를 제거하기위한 편의로 볼 수도 있습니다.

케이스 클래스를 구성 할 때 Scala는 다음을 제공합니다.

  • 클래스와 동반자 객체를 만듭니다.
  • 동반 객체 apply는 팩토리 메소드로 사용할 수 있는 메소드를 구현합니다 . 새 키워드를 사용할 필요가없는 구문 설탕 이점을 얻을 수 있습니다.

클래스는 불변이므로 접근자는 클래스의 변수 또는 속성이지만 뮤 테이터는 없습니다 (변수를 변경할 수 없음). 생성자 매개 변수는 공개 읽기 전용 필드로 자동으로 사용 가능합니다. Java bean 구문보다 사용하기가 훨씬 좋습니다.

  • 당신은 또한 얻을 hashCode, equals그리고 toString기본적으로 방법과 equals방법은 구조적으로 객체를 비교합니다. copy방법 (일부 필드 방법에 제공된 새로운 값을 갖는) 개체를 복제 할 수 있도록 생성된다.

앞에서 언급했듯이 가장 큰 장점은 사례 클래스에서 패턴 일치를 할 수 있다는 것입니다. 그 이유 unapply는 케이스 클래스를 해체하여 필드를 추출 할 수있는 메소드를 가져 오기 때문 입니다.


본질적으로 케이스 클래스 (또는 클래스가 인수를 취하지 않으면 케이스 객체)를 만들 때 스칼라에서 얻는 것은 팩토리추출기 로 목적을 제공하는 단일 객체입니다 .


답변

사람들이 이미 말한 것 외에도 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