Scala
- 객체 지향 언어 + 함수형 언어
- JVM 위에서 동작해 자바의 모든 라이브러리 사용 가능
객체
- 스칼라는 기본 자료형, 함수, 클래스 등 모든 것을 객체 취급
object | description |
---|
Unit | 리턴값이 없음을 표현 |
Option | 값이 있거나 없는 상태를 표현 |
*==, != 연산자로 문자열/객체 등 비교 가능
자료형
- 자료형은 자바와 동일하면서 모든 것이 클래스
- 변수 타입을 선언하지 않으면 컴파일러가 자동으로 정수형은 Int, 실수형은 Double로 선언
기본 자료형 | 참조 자료형 |
---|
Byte, Short, Int, Long, Float, Double, Char, Boolean | String, Unit, Null, Nothing, Any, AnyVal, AnyRef |
scala> s = b // 업캐스팅은 자동으로 진행 (8bit > 16bit)
scala> i = l // error: 64bit > 32bit
<console> error: type mismatch;
...
scala> i = l.toInt // 다운캐스팅은 변환 메소드를 이용해 명시적으로 진행
// 암시적 선언
scala> var x = 10
// 명시적 선언
scala> var b: Byte = 10
scala> var f = 10.0f
문자열
- 문자열은 쌍따옴표("), 멀티라인 문자열은 세 개의 쌍따옴표(""") 이용
// 접두어 s: ${변수명}으로 문자열 안의 변수를 값으로 치환
scala> val name = "David"
scala> println(s"Hello ${name})
Hello David
scala> println(s"${1+1}")
2
// 접두어 f: 문자열 format 처리
scala> val height:Double = 182.3
scala> val name = "James"
scala> println(f"$name%s is $height%2.2f meters tall")
James is 182.30 meters tall
// 접두어 raw: 특수 문자를 처리하지 않고 원본 문자로 인식
scala> raw"David\n\nJames"
res0: String = David\n\nJames
변수
가변 변수 var | 불변 변수 val |
---|
재할당 가능 | 재할당 불가능 (오류 발생) |
| 데이터를 단순하게 처리할 수 있음 |
함수
- 리턴문/리턴 타입은 생략 가능하지만 매개변수의 파라미터 타입은 생략 불가능
- 리턴값이 없는 함수를 선언할 때는 Unit을 이용
- 리턴문이 생략되고 리턴 타입이 Unit이 아니면, 함수의 마지막 값을 리턴
scala> def add(x: Int, y: Int): Int = { return x+y } // 함수 선언
scala> def add(x: Int): Int = { x = 10 } // x는 val이므로 변경 불가
scala> def add(x: Int, y: Double) = { x+y } // 리턴 타입 생략
scala> def add(x: Int, y: Int): Unit = { println(x+y) } // 리턴 데이터가 없는 경우 Unit 선언
scala> def add(x: Int, y: Int) = { println(x+y) } // 리턴 타입 Unit도 생략
scala> def printUpper(msg:String):Unit = println(msg.toUpperCase()) // {} 없이 선언 가능
scala> def printLower(msg:String) = println(msg.toLowerCase()) // 리턴 타입 생략
// 파라미터 기본값 설정
scala> def add(x: Int, y: Int=10) = { println(x+y) } // y에 기본값
scala> add(1)
11
scala> add(10, 3)
13
- 같은 타입의 개수가 다른 가변 길이의 파라미터를 입력받을 때 *를 이용하면 Seq형으로 변환되어 입력
scala> def sum(num: Int*) = num.reduce(_+_)
scala> sum(1, 2, 3)
res0: Int = 6
- 함수를 var/val로 선언하면 함수를 실행해 그 반환값을 변수에 저장
scala> val random1 = Math.random() // random1과 random2는 선언 시점에 값 확정 scala> var random2 = Math.random()
scala> def random3 = Math.random() // 실행 시점에 값 확정
scala> def run() {
| def middle() {
| println("middle")
| }
| println("start")
| middle()
| println("end")
| }
scala> run
start
middle
run
1) 람다 함수
- 언더바 _를 이용해 묵시적인 파라미터 지정 가능
- 묵시적인 파라미터를 이용할 때는 언더바의 위치에 따라 파라미터 선택
// exec는 3개의 파라미터(함수 f, x, y)
scala> def exec(f: (Int, Int) => Int, x: Int, y: Int) = f(x, y)
scala> exec((x: Int, y: Int) => x+y, 2, 3) // 람다 함수(x+y) 전달
res0: Int = 5
scala> exec((x, y) => x+y, 7, 3) // 함수 선언 시 타입을 입력했기 때문에 추가적인 설정 없이도 처리 가능
res1: Int = 10
scala> exec((x, y) => x-y, 7, 3)
res2: Int = 4
scala> exec(_+_, 3, 1) // 언더바 _를 이용해 묵시적인 처리
res3: Int = 4
2) 커링
- 여러 개의 인수 목록을 여러 개의 괄호로 정의할 수 있음
- 함수를 정해진 인수의 수보다 적은 인수로 호출하면 그 리턴 값은 나머지 인수를 받는 함수
- 커링을 이용해 파라미터 값을 미리 바인딩 하는 다른 함수로 선언하거나, 다른 함수의 파라미터로 전달할 수 있음
// x를 n으로 나누어 나머지가 0인지 확인하는 함수
scala> def modN(n: Int)(x: Int) = ((x%n) == 0)
// 커링을 이용해 modN 함수를 n 값이 정해진 변수로 호출
scala> def modOne:Int => Boolean = modN(1)
scala> def modTwo = modN(2) _
scala> println(modOne(4))
true
scala> println(modTwo(5))
false
3) 클로저
- 내부에 참조되는 모든 인수에 대한 묵시적 바인딩을 지닌 함수로 자신이 참조하는 것들의 문맥 포함
- 클로저 블록에 코드를 바인딩함으로써 그 블록의 실행을 나중으로 연기할 수 있음 (지연 실행)
scala> def divide(n:Int) = (x:Int) => { x/n } // divide는 x/n인 함수 반환
scala> def divideFive = divide(5) // n에 5를 바인딩
scala> println(divideFive(10))
2
scala> var factor = 10
scala> def multiplier = (x:Int) => x*factor
scala> println(multiplier(4))
40
4) 타입
- 타입을 이용해 클래스와 함수를 제네릭하게 생성 가능
// 클래스 적용
scala> import scala.collection.mutable // scala는 기본적으로 불변 데이터를 이용하기 때문에 변경가능한 스택처리를 위해 import 추가
scala> trait TestStack[T] { // trait: scala에서의 interface
| def pop():T
| def push(value:T)
| }
scala> class StackSample[T] extends TestStack[T] {
| val stack = new scala.collection.mutable.Stack[T]
| override def pop(): T = {
| stack.pop()
| }
| override def push(value:T) {
| stack.push(value)
| }
| }
scala> val s = new StackSample[String]
scala> s.push("1")
scala> s.push("2")
scala> s.pop()
1
scala> s.pop()
2
// 메소드 적용
scala> def sample[K](key:K) { println(key) }
scala> def sample2 = sample[String] _
scala> sample2("Hello")
Hello