without haste but without rest
Scala Book memo 본문
Scala Book
Summary
스칼라의 컨셉과 언어의 목적에 대해서 간단히 살펴보고 loop, condition, class, method 등을 빠르게 훑는다.
Concept
Scalable한 언어라 'Scala' 라는 이름을 붙였다. JVM 기반 언어이며 주로 데이터 처리를 위한 목적으로 많이 사용한다.
스칼라는 스칼라로 쓰였다는데 이 내용이 정확히 의미하는 바에 대해서 찾아보기.
val & var
val a = 1
var b = 1
val은 value로 변수를 한 번 선언하면 값을 변경할 수 없다.
var는 variable로 변수를 선언하고 난 이후에 변경할 수 있다.
Object
오브젝트는 자바의 static class member와 유사하다. 스칼라에서는 정적 변수가 없다. 대신에 object를 이용해서 싱글톤 객체를 생성한다. 단일 객체만 존재하는 클래스라고 할 수 있다.
오브젝트 내에서 자바처럼 main 메서드를 통해 프로그램을 실행할 수 있다.
object Hello {
def main(args: Array[String]) = {
greeting("Jinung")
}
def greeting(name: String): Unit = {
println("Hello " + name)
}
}
App 상속
더욱 간편한 방법으로 스칼라 북에서는 버전2라고 소개하고있다.
object Hello2 extends App {
greeting("Jinung")
def greeting(name: String): Unit = {
println("Hello " + name)
}
}
Loop
for 문에서 괄호를 쓰는데, <- 문자를 추가해주어야 한다.
scala> val nums = Seq(1,2,3)
nums: Seq[Int] = List(1, 2, 3)
scala> for (n <- nums) println(n)
1
2
3
응용 버전
object Main extends App{
for (number <- 0 to 10 by 2) println(number)
}
number 변수에 0부터 10까지 단위는 2로 건너뛰며 변수를 전달한다. (이때 파이썬처럼 이터레이터 객체를 생성하는지는 잘 모르겠다.)
to는 많은 프로그래밍 랭귀지에서 사용하는 미만 범위가 아니라 포함이다. 미만으로 사용하고자 하는 경우에는 until을 사용한다.
While
object Main extends App{
var num = 0
while (num < 10) {
println(num)
num = num + 1
}
}
Condition
자바의 조건문과 형태가 같다.
if (test1) {
doX()
} else if (test2) {
doY()
} else {
doZ()
}
Class
Basic Class
class Person(var firstName: String, var lastName: String)
val p = new Person("Bill", "Panner")
필드에 접근하는 방법
자바의 경우 getter, setter를 별도로 구현하는 게 일반적인 방법인데, 스칼라는 그냥 바로 접근하게 하나보다.
scala> p.firstName = "William"
p.firstName: String = William
scala> p.lastName = "Bernheim"
p.lastName: String = Bernheim
Example
object Hello2 extends App {
val p = new Person("Jinung", 27)
val name = p.showName()
println(name)
}
class Person(val name: String, var age: Int) {
def getName(): String = {
name
}
def getAge(): Int = {
age
}
}
Method
클래스 내부에서만 선언하는 게 아닌데, 왜 메서드인지 잘 모르겠다.
모든 변수가 객체라서 그런것인지 더 확인해보기
간단한 메서드
def addThenDouble(a: Int, b: Int): Int = {
val sum = a + b
val doubled = sum * 2
doubled
}
문법이 조금 헷갈릴 수 있는 부분인데 addThenDouble 함수는 Int 타입을 반환한다. 이때 메서드의 내부 블록에서 마지막에 등장하는 doubled가 반환할 값이다. (스칼라는 return이 없다. 충 격)
아래와 같은 형태로도 선언할 수 있다.
def double(a: Int) = a * 2
double(a: Int): 메서드 명과 변수 타입 선언
= a * 2 : 변수에 2를 곱한 값을 리턴
Trait & Abstact Class
Trait은 인터페이스 목적으로 사용할 수 있다. Abstact Class는 자바의 그 추상 클래스가 맞다.
차이점은 Trait은 Constructor 변수를 선언하지 못한다.
*인터페이스와 추상 클래스의 차이점
인터페이스는 모든 메서드가 추상 메서드. 추상 클래스는 일부분만 추상 메서드일 수 있다.
추상 클래스는 이를 상속 받는 하위 클래스가 추상 메서드를 확장해서 사용할 목적이다.
반면 인터페이스는 껍데기만 규정해서 함수의 구현을 강제하는 목적으로 사용한다.
Trait Example
trait TailWagger {
def startTail(): Unit
def stopTail(): Unit
}
Java Style
public interface TailWagger {
public void startTail();
public void stopTail();
}
Extending a Trait
trait TailWagger {
def startTail(): Unit
def stopTail(): Unit
}
class Dog extends TailWagger {
// the implemented methods
def startTail(): Unit = println("tail is wagging")
def stopTail(): Unit = println("tail is stopped")
}
Trait은 여러 개도 상속할 수 있다.
Abstact Class
스칼라의 추상 클래스 컨셉은 자바의 추상 클래스와 유사하다. 그런데 스칼라에서는 트레잇의 기능이 막강해서 추상 클래스를 쓸 일이 거의 없다. 스칼라에서 추상 클래스를 쓰는 경우는 다음과 같다.
- 컨스트럭터를 필요로 하는 베이스 클래스 생성을 원하는 경우
- 스칼라 코드를 자바에서도 호출하고자 하는 경우
다음과 같이 트레잇은 컨스트럭터 파라미터를 허용하지 않는다.
// this won’t compile
trait Animal(name: String)
그러므로 컨스트럭터 파라미터를 사용하고자 하는 경우 추상 클래스를 사용한다.
abstract class Animal(name: String)
Extending Example
abstract class Pet (name: String) {
def speak: Unit = println(s"My name is $name")
}
class Dog(name: String) extends Pet(name)
val d = new Dog("Fido")
d.speak
여기서 의문
트레잇은 파라미터를 허용하지 않는데 이러한 경우, 트레잇을 상속하는 다른 클래스는 리스코브 원칙을 만족시킬 수 있는가?
Pure Function
함수가 함수 외부에 무언가에 의존하지 않고 작동하는 것을 Pure Function이라고 부른다.
Scala Collections
스파크 학습 하면서 필요한 부분은 계속해서 업데이트...