수색…


통사론

  • case 클래스 Foo () // 매개 변수가없는 사례 클래스는 빈 목록을 가져야합니다
  • case 클래스 Foo (a1 : A1, ..., aN : AN) // a1 ... aN 필드를 갖는 case 클래스를 만든다.
  • case 객체 바 // 싱글 톤 case 클래스 생성

사례 클래스 평등

사례 클래스별로 무료로 제공되는 기능 중 하나는 개체의 참조 평등을 검사하는 대신 모든 개별 멤버 필드의 값이 같은지 확인하는 자동 생성 equals 메서드입니다.

일반 수업 :

class Foo(val i: Int)
val a = new Foo(3)
val b = new Foo(3)
println(a == b)// "false" because they are different objects

사례 클래스 사용 :

case class Foo(i: Int)
val a = Foo(3)
val b = Foo(3)
println(a == b)// "true" because their members have the same value

생성 된 코드 아티팩트

case 변경자는 스칼라 컴파일러가 클래스에 대한 공통적 인 상용구 코드를 자동으로 생성하도록합니다. 이 코드를 수동으로 구현하는 것은 지루하고 오류의 원인입니다. 다음 케이스 클래스 정의 :

case class Person(name: String, age: Int)

... 다음 코드가 자동으로 생성됩니다.

class Person(val name: String, val age: Int)
  extends Product with Serializable
{
  def copy(name: String = this.name, age: Int = this.age): Person =
    new Person(name, age)

  def productArity: Int = 2

  def productElement(i: Int): Any = i match {
    case 0 => name
    case 1 => age
    case _ => throw new IndexOutOfBoundsException(i.toString)
  }

  def productIterator: Iterator[Any] =
    scala.runtime.ScalaRunTime.typedProductIterator(this)

  def productPrefix: String = "Person"

  def canEqual(obj: Any): Boolean = obj.isInstanceOf[Person]

  override def hashCode(): Int = scala.runtime.ScalaRunTime._hashCode(this)

  override def equals(obj: Any): Boolean = this.eq(obj) || obj match {
    case that: Person => this.name == that.name && this.age == that.age
    case _ => false
  }

  override def toString: String =
    scala.runtime.ScalaRunTime._toString(this)
}

대 / case 수정자는 대등 객체도 생성합니다.

object Person extends AbstractFunction2[String, Int, Person] with Serializable {
  def apply(name: String, age: Int): Person = new Person(name, age)

  def unapply(p: Person): Option[(String, Int)] =
    if(p == null) None else Some((p.name, p.age))
}

object 적용하면 대 / case 수정자는 비슷한 효과를 나타냅니다 (효과는 적지 만). 여기서 주요한 이득은 toString 구현과 여러 프로세스에서 일관된 hashCode 값입니다. 대 / 소문자의 객체는 참조 평등을 사용합니다 (정확하게).

object Foo extends Product with Serializable {
  def productArity: Int = 0

  def productIterator: Iterator[Any] =
    scala.runtime.ScalaRunTime.typedProductIterator(this)

  def productElement(i: Int): Any =
    throw new IndexOutOfBoundsException(i.toString)

  def productPrefix: String = "Foo"

  def canEqual(obj: Any): Boolean = obj.isInstanceOf[this.type]

  override def hashCode(): Int = 70822 // "Foo".hashCode()

  override def toString: String = "Foo"
}

클래스 자체와 그 부속 오브젝트 모두에서 case 수식어가 제공하는 메소드를 수동으로 구현하는 것은 여전히 ​​가능합니다.

사례 클래스 기본 사항

일반 클래스와 비교하여 사례 클래스 표기법은 다음과 같은 몇 가지 이점을 제공합니다.

  • 모든 생성자 인수는 public 이며 초기화 된 객체에서 액세스 할 수 있습니다 (일반적으로 여기서는 설명하지 않습니다).

    case class Dog1(age: Int)
    val x = Dog1(18)
    println(x.age) // 18 (success!)
    
    class Dog2(age: Int)
    val x = new Dog2(18)
    println(x.age) // Error: "value age is not a member of Dog2"
    
  • toString , equals , hashCode (속성에 기반), copy , applyunapply 메소드를 구현합니다.

    case class Dog(age: Int)
    val d1 = Dog(10)
    val d2 = d1.copy(age = 15)
    
  • 패턴 일치를위한 편리한 메커니즘을 제공합니다.

    sealed trait Animal // `sealed` modifier allows inheritance within current build-unit only
    case class Dog(age: Int) extends Animal
    case class Cat(owner: String) extends Animal
    val x: Animal = Dog(18)
    x match {
        case Dog(x) => println(s"It's a $x years old dog.")
        case Cat(x) => println(s"This cat belongs to $x.")
    }
    

사례 클래스 및 Immutabilty

Scala 컴파일러는 기본적으로 매개 변수 목록의 모든 인수 앞에 valval 입니다. 즉, 기본적으로 사례 클래스는 변경되지 않습니다. 각 매개 변수에는 접근 자 메서드가 있지만 mutator 메서드는 없습니다. 예 :

case class Foo(i: Int)

val fooInstance = Foo(1)
val j = fooInstance.i       // get
fooInstance.i = 2           // compile-time exception (mutation: reassignment to val)

case 클래스의 매개 변수를 var 로 선언하면 기본 비헤이비어가 무시되고 case 클래스를 변경할 수 있습니다.

case class Bar(var i: Int)

val barInstance = Bar(1)
val j = barInstance.i       // get
barInstance.i = 2           // set

case 클래스가 'mutable'인 또 다른 인스턴스는 case 클래스의 값이 변경 가능할 때입니다.

import scala.collection._

case class Bar(m: mutable.Map[Int, Int])

val barInstance = Bar(mutable.Map(1 -> 2))
barInstance.m.update(1, 3)                  // mutate m
barInstance                                 // Bar(Map(1 -> 3)

여기에서 발생하는 '돌연변이'지도에 유의 m 하지 않도록에 포인트를 m 자체. 따라서, 어떤 다른 객체가 멤버로서 m 을 가졌다면, 변화를 볼 수있을 것이다. 방법 다음 예제 변경 참고 instanceA 도 변경 instanceB :

import scala.collection.mutable

case class Bar(m: mutable.Map[Int, Int])

val m = mutable.Map(1 ->2)
val barInstanceA = Bar(m)
val barInstanceB = Bar(m)
barInstanceA.m.update(1,3)
barInstanceA  // Bar = Bar(Map(1 -> 3))
barInstanceB  // Bar = Bar(Map(1 -> 3))
m  // scala.collection.mutable.Map[Int,Int] = Map(1 -> 3)

특정 변경 사항이있는 객체의 복사본 만들기

사례 클래스는 특정 변경 사항을 사용하여 이전 필드와 동일한 필드를 공유하는 새 개체를 만드는 copy 메서드를 제공합니다.

이 기능을 사용하여 이전과 동일한 특성을 가진 새 객체를 만들 수 있습니다. 이 간단한 사례 클래스는이 기능을 보여줍니다.

case class Person(firstName: String, lastName: String, grade: String, subject: String)
val putu = Person("Putu", "Kevin", "A1", "Math")
val mark = putu.copy(firstName = "Ketut", lastName = "Mark")
// mark: People = People(Ketut,Mark,A1,Math)

이 예제에서 두 객체는 ​​copy ( firstNamelastName )에 지정된 위치를 제외하고 유사한 특성 ( grade = A1 , subject = Math )을 공유한다는 것을 알 수 있습니다.

형식 안전을위한 단일 요소 사례 클래스

타입 안전성을 얻으려면 때때로 우리 도메인에서 원시 타입의 사용을 피하고 싶습니다. 예를 들어, name 가진 Person 을 상상해보십시오. 통상, nameString 로서 encode합니다. 다만, Personname 을 나타내는 String 와 에러 메세지를 나타내는 String 를 혼용하는 것은 어렵지 않습니다.

def logError(message: ErrorMessage): Unit = ???
case class Person(name: String)
val maybeName: Either[String, String] = ??? // Left is error, Right is name
maybeName.foreach(logError) // But that won't stop me from logging the name as an error!

이러한 함정을 피하기 위해 다음과 같이 데이터를 인코딩 할 수 있습니다.

case class PersonName(value: String)
case class ErrorMessage(value: String)
case class Person(name: PersonName)

PersonNameErrorMessage 또는 일반 String 섞어 사용하면 코드가 컴파일되지 않습니다.

val maybeName: Either[ErrorMessage, PersonName] = ???
maybeName.foreach(reportError) // ERROR: tried to pass PersonName; ErrorMessage expected
maybeName.swap.foreach(reportError) // OK

그러나 이것은 우리가 이제 PersonName 컨테이너에 /에서 String 을 box / unbox해야하기 때문에 런타임 오버 헤드가 적다. 이를 피하기 위해 PersonNameErrorMessage 값 클래스를 만들 수 있습니다.

case class PersonName(val value: String) extends AnyVal
case class ErrorMessage(val value: String) extends AnyVal


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow