Scala 설치
$ brew install scala
Scala
-
확장 가능한 언어(SCAlable LAnguage)의 약자
-
2003년 마틴 오더스키(Martin Odersky) 교수와 EPFL(로잔 공과 대학)의 연구진이 JVM 플랫폼에서 FP와 OOP를 동시에 지원하는, 성능이 우수한 환경을 제공하기 위해 이 언어를 만듬
-
JVM 언어로 자바 런타임을 사용
-
REPL(Real-Eval-Print-Loop) 셸 제공
-
정적 타입 지원
- 정적 타입 언어
-
컴파일 시간에 변수의 타입을 알게 되면 정적 타입 언어라고 함
타입
-
Any
: 모든 타입들의 슈퍼타입, 직접적으로 두 개의 서브타입을 가지고 있음(AnyVal
,AnyRef
) -
AnyVal
: 모든 값 타입의 루트, 9개의 값 타입이 있음(Double
,Float
,Long
,Int
,Short
,Byte
,Char
,Unit
,Boolean
) -
AnyRef
: 모든 참조 타입의 루트,java.lang.Object
에 해당 -
Noting
: 모든 타입의 서브타입(바텀타입) -
Null
: 모든 참조 타입의 서브타입 -
Char
: 숫자형 데이터 타입에도 등장할 수 있는 유일한 타입. String 타입의 기본이 되는 타입으로 단일 문자. Char 리터럴은 single quoter로 작성 -
Boolean
: true 혹은 boolean. 다른 언어들과 달리 불이 아닌 다른 값을 변환하지 않음(숫자 0은 false와 다름) -
Unit
: 데이터 타입을 나타내는 대신 데이터가 없음을 나타냄. Unit 리터럴은 빈 괄호.val nada = ()
Tuple
-
튜플은 둘 이상의 값을 가지는 순서가 있는 컨테이너
구문: 튜플 생성// ( <값 1>, <값 2[, <값 3>...] ) val info = (5, "Korben", true)
-
튜플의 각 항목은 1부터 시작하는 인덱스를 이용하여 접근 가능
val name = info._2
-
화살표 연산자(
→
)를 사용하는 방식도 존재. 튜플에서 키-값 쌍을 표현하는 가장 보편적인 방법scala> val red = "red" -> "0xff0000" red: (String, String) = (red, 0xff0000) scala> val reversed = red._2 -> red._1 reserved: (String, String) = (0xff0000,red)
String
-
multiline literal, interpolation(보간) 기능 추가
-
자바와 달리 등호 연산자(
==
)는 객체 참조가 같은지 검사하지 않고 실제 값이 같은지 검사함 -
여러 줄의 String인 double quoter 세 개를 이용하여 생성
// 특수 문자의 시작을 나타내는 역슬래시를 인지하지 못함 scala> val str = """She suggested reformatting the file | by replacing tabs(\t) with newlines (\n); | "Why do that?", he asked. """ str: String = "She suggested reformatting the file by replacing tabs(\t) with newlines (\n); "Why do that?", he asked. "
-
문자열 보간(string interpolation)은 첫 큰 따옴표 전에 접두사
s
를 추가하여 표기.scala> println(s"Pi, using 355/113, is about $approx.") Pi, using 355/113, is about 3.141593. scala> val item = "apple" item: String = apple scala> s"How do you like them ${item}s?" res0: String = How do you like them apples? scala> s"Fish n chips n vinegar, ${"pepper " * 3}salt" res1: String = Fish n chips n vinegar, pepper pepper pepper salt
-
문자열 보간의 또 다른 포맷은 printf 표기법을 사용하는 것(접두사
f
사용)scala> val item = "apple" item: String = apple scala> f"I wrote a new $item%.3s today" // (1) res0: String = I wrote a new app today scala> f"Enjoying this $item ${355/113.0}%.5f times today" // (1) res1: String = Enjoying this apple 3.14159 times today
-
printf 표기법이 읽기는 다소 어렵지만, 출력을 근본적으로 제어할 수 있는 장점
-
Rich Wrapper classes
-
스칼라에는 원시(primitive) 데이터 타입 개념 없음
-
Java의 primitive 타입을 표현하는데 사용
문법
선언
-
값과 변수는 관례상 소문자로 시작 → camelCas
-
문자, 숫자, 연산자 기호 사용 가능
Note
|
연산자(operator)
\u0020에서 \u007F 사이의 문자와 유니코드 Sm[Symbol/Math] 카테고리에서 대괄호와 마침표를 제외한 모든 문자 |
-
스칼라에서는 연산자 오버로딩을 지원하지 않음
-
연산자는 단순히 메서드
-
메서드 이름이
:
으로 끝나면 오른쪽 결합이 된다.scala> val my_list = List(1, 2, 3, 4) my_list: List[Int] = List(1, 2, 3, 4) scala> val my_result1 = my_list :+ 5 my_result1: List[Int] = List(1, 2, 3, 4, 5) scala> val my_result2 = 0 +: my_list my_result2: List[Int] = List(0, 1, 2, 3, 4)
Variable
-
mutable한 값
-
변수에 재할당은 가능하지만 지정된 타입을 바꿀 수는 없음
var
var <name>: <type> = <literal>
scala> var x: Int = 5
x: Int = 5
scala> x = 3
x: Int = 3
Value
-
immutable한 값
-
데이터를 통해 타입 추론(type inference)이 가능하여 type을 생략할 수 있음
val
val <name>[: <type>] = <literal>
scala> val x: Int = 5
x: Int = 5
scala> x = 3
^
error: reassignment to val
Lazy Value
-
Regular Expression
-
자바 클래스
java.util.regex.Pattern
에 기반함 -
String 타입은 정규 표현식을 지원하는 built-in 연산을 제공
-
matches
scala> "Froggy went a' courting" matches ".*courting" res0: Boolean = true
-
replaceAll
scala> "milk, tea, muck" replaceAll ("m[^ ]+k", "coffie") res0: String = coffie, tea, coffie
-
replaceFirst
scala> "milk, tea, muck" replaceFirst ("m[^ ]+k", "coffie") res0: String = coffie, tea, muck
-
-
정규표현식으로 값 캡쳐하기
-
r
연산자를 호출하여 문자열을 정규 표현식 타입으로 전환 -
Regex 인스턴스를 반환
-
Capture Group은 정규 표현식 패턴을 기반으로 주어진 문자열에서 항목을 선택하고 이를 로컬 값으로 전환할 수 있게 해줌
-
패턴은 최소 하나의 괄호로 정의된 캡처 그룹을 포함해야 함
-
역슬래시를 인식하기 위해 multiline string을 사용
scala> val input = "Enjoying this apple 3.14159 times today" input: String = Enjoying this apple 3.14159 times today scala> val pattern = """.* apple ([\d.]+) times .*""".r (1) pattern: scala.util.matching.Regex = .* apple ([\d.]+) times .* (2) scala> val pattern(amountText) = input amountText: String = 3.14159 (3) scala> val amount = amountText.toDouble amount: Double = 3.14159 (4)
-
.r
을 붙혀 Regex 인스턴스를 반환 받음 -
정규표현식 타입은
scala.util.matching.Regex
또는 간단히util.matching.Regex
-
val <regex value>(<name>) = <input string>
-
Convert String type to Double type
-
-
-
조건문, 반복문
표현식
표현식(expression)은 값을 반환하는 코드의 단위
val <name>[: <type> = <expression>
var <name>[: <type> = <expression>
표현식 블록(expression block)
scala> val x = 5 * 20; val amount = x + 10
x: Int = 100
amount: Int = 110
scala> val amount = {val x = 5 * 20; x + 10} // (1)
amount: Int = 110
-
블록의 마지막 표현식은 블록의 반환값을 결정한다.
scala> val amount = {
val x = 5 * 20
x + 10
}
amount: Int = 110
문장
-
문장(statement)은 값을 반환하지 않는 표현식
-
문장의 반환 타입은 값이 없음을 나타내는 Unit
-
아래 코드의 값 정의는 어떤 것도 반환하지 않기 때문에 문장에 해당함
scala> val x = 1 x: Int = 1
If .. Else expression block
-
스칼라는 하나의 'if’와 선택적인 'else' 블록만을 지원
-
'else if' 블록을 단일 구성체로 인식하지 않음
-
스칼라에서 if와 else 블록은 한 줄에 간결하게 맞아떨어지기 때문에 삼항 표현식이 실제로 필요하지 않음
// if (<부울식>) <표현식>
// if (<부울식>) <표현식> else <표현식>
scala> if (47 % 3 > 0 ) println("Not a multiple of 3")
Not a multiple of 3
scala> val result = if ( false ) "what does this return?"
result: Any = ()
scala> val x = 10; val y = 20
x: Int = 10
y: Int = 20
scala> val max = if (x > y) x else y
max: Int = 20
Match Expression
-
자바의 'switch’문과 유사
-
표현식은 단 하나의 패턴만 매칭할 수 있으므로 여러 개의 패턴을 한 번에 순서대로 매칭하는 형태의 제어 이동(fall-through)이 없음
-
중간에 그 제거 이동에서 빠져나오는 'break' 문도 없음
-
-
실제로 대부분 스칼라 개발자는 'if..else' 블록보다 매치 표현식을 더 선호. 표현력이 좋고 구문이 간결하기 때문
-
여러 패턴을 하나로 결합하여 그 패턴 중 하나라도 일치하면 case 블록을 동작시키려면 패턴 대안(pattern alternative)
-
매칭되는 것이 없는 에러를 예방하려면 wildcard match-all 패턴 사용
-
패턴 가드(pattern guard)는 값 바인딩 패턴에 if 표현식을 추가하여 match 표현식에 조건부 로직을 섞어 쓸 수 있음
<expression> match {
case <pattern match> => <expression>
[case...]
}
scala> val x = 10; val y = 20;
x: Int = 10
y: Int = 20
scala> val max = x > y match {
case true => x
case false => y
}
max: Int = 20
scala> val status = 500
status: Int = 500
scala> val message = status match {
case 200 =>
"ok"
case 400 => {
println("ERROR - we called the service incorrectly")
"error"
}
case 500 => {
println("ERROR - the service encountered an error")
"error"
}
}
ERROR - the service encountered an error
message: String = error
scala> val day = "MON"
day: String = MON
scala> val kind = day match {
case "MON" | "TUE" | "WED" | "THU" | "FRI" =>
"weekday"
case "SAT" | "SUN" =>
"weekend"
}
kind: String = weekday
scala> val message = "OK"
message: String = OK
scala> val status = message match {
case "OK" => 200
case other => { // (1)
println(s"Couldn't parse $other")
-1
}
}
status: Int = 200
-
other
는 case 블록이 유지되는 동안 정의
scala> val message = "Unauthorized"
message: String = Unauthorized
scala> val status = message match {
case "Ok" => 200
case _ => {
println(s"Couldn't parse $message")
-1
}
}
Couldn't parse Unauthorized
status: Int = -1
함수
-
return 키워드는 선택적이기 때문에 스칼라 컴파일러는 return 키워드가 없으면 마지막 할당 값을 리턴하게 설계됨
중첩 함수
nested function
for comprehensions
Implicit
monad
Collection
Import문
import math._ // (1)
import math.{sin, cos} // (2)
import scala.collection.mutable.{Map => MutableMap} // (3)
import math.{cos => _, _} // (4)
-
_
(underscore) 는 Java의*
(asterisk)와 비슷하게 와일드카드로, math 패키지의 모든 것을 import 한다. -
{ }
를 통해 math 패키지에 일부만 import 한다. -
이름을 변경해서 import 할 수 있다.
-
math 패키지를 모두 import하지만 cos는 안보이게 한다.
컬렉션
Currying
객체지향
생성자
보조 생성자
오브젝트
-
정적메서드 대신 오브젝트
-
클래스의 컴패니언
트레이트
trait
-
트레이트는 타입 파라미터만 가질 수 있다