4장 classes and objects - codeport/scala GitHub Wiki

drypot님의 한글 번역

Class, fields, and methods

  • Class를 선언하고, Object를 만드는 방법
class ChecksumAccumulator {
  var sum = 0
}

val acc = new ChecksumAccumulator
val csa = new ChecksumAccumulator

// Won’t compile, because acc is a val
acc = new ChecksumAccumulator
  • 필드는 인스턴스변수라고도 부른다.
  • private으로 멤버변수를 선언하려면 앞에 private라고 쓴다
  • 스칼라의 기본 접근레벨은 public이다
  • 메서드 파라미터는 val이다.
  • return문이 없으면 마지막 값이 리턴된다(return문을 쓰지 않는 것과 여러곳에서 return하지 않는 것을 권한다.)
class ChecksumAccumulator {
  private var sum = 0
  def add(b: Byte): Unit = {
    sum += b
  }

  def checksum(): Int = { 
    return ~(sum & 0xFF) + 1
  }
}

// Example
def add(b: Byte): Unit = {
  b = 1     // This won’t compile, because b is a val
  sum += b
}
  • 메서드가 하나의 표현식만 있으면 중괄호를 없앨수 있고 def부터 한줄로 쓸 수 있다
class ChecksumAccumulator {
  private var sum = 0
  def add(b: Byte): Unit = sum += b
  def checksum(): Int = ~(sum & 0xFF) + 1
}
  • 사이드 이펙트가 있을 수 있는 메서드는 Unit 리턴타입 이용해 표현할 수 있다. =를 제거하고 바디를 중괄호로 감싸는 것도 같은 의미다.
scala> def f(): Unit = "this String gets lost"
f: ()Unit
scala> def g() { "this String gets lost too" }
g: ()Unit
scala> def h() = { "this String gets returned!" }
h: ()java.lang.String
scala> h
res0: java.lang.String = this String gets returned!

Semicolon inference

  • 세미콜론은 쓰고 싶을 때만 쓴다.
  • 여러줄에 문장을 쓰려면 괄호로 묶거나 오퍼레이터를 문장의 마지막에 쓴다
  • 줄의 끝이 곧 세미콜론이다. 단, 아래 3가지 경우는 제외한다.
    • line의 마지막 글자가 문장의 끝이 될 수 없는 글자인 경우 (마침표 또는 infix operator)
    • 다음 문장이 다음 문장의 처음으로 올 수 없는 단어로 시작된 경우
    • 여러 문장이 들어갈 수 없는 소괄호(...)나 대괄호[...] 안에서 줄바꿈 된 경우
x 
+ y
// 이는 `x`와 `+y`다. 한문장으로 하려면..
(x
+ y)
// or
x +
y +
z

Singleton objects

스칼라에서 클래스는 static 맴버를 가질 수 없다. 대신에 싱글톤 오브젝트(singleton objects)를 제공하며, 오브젝트 정의시 class 키워드 대신에 object를 사용한다.

// In file ChecksumAccumulator.scala
import scala.collection.mutable.Map
object ChecksumAccumulator {
  private val cache = Map[String, Int]()
  def calculate(s: String): Int =
    if (cache.contains(s))
      cache(s)
    else {
      val acc = new ChecksumAccumulator
      for (c <- s)
        acc.add(c.toByte)
      val cs = acc.checksum()
      cache += (s -> cs)
      cs
  }
}

싱글톤오브젝트가 클래스와 같은 이름일 때 이것을 클래스의 companion object라고 부르며, 클래스와 companion object는 같은 소스파일에 있어야 한다. object와 같은 이름을 가진 클래스는 companion class라고 부르고, 서로간 private member에 접근할 수 있다.

싱글톤 오브젝트는 Java의 static 메서드로 간주 할 수 있다.

ChecksumAccumulator.calculate("Every value is an object.")

싱글톤 오브젝트는 단순히 스테틱 메서드를 담고있는 객체 이상이다.

  • first-class 오브젝트이다.
  • 싱글턴 오브젝트는 수퍼클래스를 확장하고 trait를 믹스인할 수 있다.

클래스와 싱글톤 오브젝트의 차이점

  • 싱글톤 오브젝트는 new 키워드로 instantiate할 수 없기 때문에 파라미터를 전달할 수 없다.

companion class와 같은 이름이 아닌 싱글톤 오브젝트를 standalone object라고 부른다.

A Scala application

  • 스칼라는 묵시적으로 java.langscala를 import한다. 그 중에 scala.Predef는 println이나 assert같은 유용한 메소드를 가지고 있다.
  • 스칼라에서는 파일명을 맘대로 할 수 있지만 찾기 쉽도록 클래스와 같은 파일명을 권한다
  • 스크립트는 결과 표현식으로 끝나야 한다
  • scalac로 파일을 컴파일 할 수 있다
  • fsc(fast Scala compiler)를 쓰면 서버데몬이 실행되고 컴파일할 파일리스트를 데몬에 보내서 즉시 컴파일 할 수 있다.
    • 처음 실행하면 데몬이 실행되고 데몬이 파일을 컴파일한다.
    • 다음으로 실행할 때는 데몬이 이미 실행중이므로 빠르게 데몬에 파일목록을 보내서 컴파일할 수 있다.
    • fsc 데몬을 멈추고 싶다면 fsc -shutdown을 사용한다.

The Application trait

  • 스칼라는 scala.Application 트레이트를 제공한다(extends Application)
  • extends Application하면 main메서드를 작성할 필요 없이 중괄호안에 바디를 적으면 자동으로 메인메서드가 된다
object Hello {
  def main(args: Array[String]): Unit = {
    println("Hello, world!")
  }
}
// 대신 다음과 같이 사용할 수 있다
object Hello extends Application {
  println("Hello, world!")
}
  • 대신 단점이 있다
    • 커맨드라인의 아규먼트를 넘길 수 없다
    • JVM 쓰레드모델의 제한때문에 멀티쓰레드 프로그램이면 명시적인 main을 사용해야 한다
    • 몇몇 JVM에서는 옵티마이징을 하지 않는다
  • 2.9부터는 Application트레이트가 deprecated되고 App 트레이트가 추가됨.
    • 지연초기화 되어서 메인메서드의 일부로 바디를 실행해서 쓰레드세이프하지 않고 VM에 최적화되지 않는 문제가 해결됨.
    • args를 통해서 커맨드라인 아규먼트를 받을 수 있다.
object Echo extends App {
  println("Echo" + (args mkString " "))
}

질문

  • p113의 주석에 java의 static import와 유사하다는게 무슨 말인가요?

kingori

  • Application 이 trait라는 걸 이제서야 알았음. 맨날 extends만 하다보니.
  • main() 의 내용이 생성자 안에서 호출이 되는 거군. (그럴 줄 알았음)
  • Application과 main() 은 서로 장/단점이 있음.
  • Application은 타자가 편하긴 하지만 간단한 앱에서만 유용.
  • command args, 멀티쓰레드, 최적화가 필요할 땐 main()
  • scalac 가 느린 건 컴파일러를 띄우기 위한 초기화 작업이 필요해서임 -> fsc를 이용하자.
  • intelliJ에선 어떻게 해야 할까?
  • 질문: 68pg 에서 언급한 synthetic class가 뭘까? $가 붙는 다는게 무슨 의미? java에서 inner class등에 $ 붙는 건 알지만.
  • companion class가 없는 singleton obj. 를 standlone object라고 부름.
  • 질문: 67pg. 마지막 줄의 내용이 뭐지? type A에선 extends하지 않고 object A가 맘대로 triat를 mixin하거나, 다른 클래스를 extends할 수 있단 소린가?
  • procedure style: function을 정의할 때 = 없이 { } 로만 감싸는 형태.
  • procedure: a method that is executed only for its side effects.