드디어 Tuple
차례입니다. 자바를 처음 시작하면서 Tuple이 없어서 정말 황당했던 기억이 나는군요;
그나저나, 계속 “튜플”로 발음했는데, 영어로 이야기하는 것을 들어보면 “터플”이 원래 발음인 것 같습니다. (그래도 저는 계속 튜플로 발음하겠습니다 적겠습니다.)
튜플은 만드는 방법은 아주 간단합니다. ( )
로 묶어 주고 요소를 ,
로 구분하면 됩니다.
다음은 문자열 세 개로 이루어진 튜플입니다.
("Apple", "Banana", "Cherry") //> (String, String, String)
튜플안에 튜플이나 리스트가 들어갈 수 있죠.
((1, 2, 3), 4, List(1, 2, 3)) // ((Int, Int, Int), Int, List[Int])
괄호로 묶어주면 되기 때문에 눈에 익기까지 시간이 약간 필요합니다.
다음처럼 튜플타입을 명시해서 만들수도 있습니다. Tuple
뒤의 숫자는 요소의 갯수입니다.
Tuple2("Hello! ", 3")
Tuple3(1, 2, 3)
다양한 타입을 묶어서 사용 할 수 있습니다.
("A", 1004, 3.14f, new Person("Brandon", 26))
//> (String, Int, Float, Person)
튜플의 요소를 가져 올 땐, 좌측부터 순서대로, _1
, _2
, _3
… 을 사용합니다.
val t = ("Apple", "Banana", "Cherry")
val a = t._1 //> a = "Apple"
val b = t._2 //> b = "Banana"
val c = t._3 //> c = "Cherry"
다음은 튜플을 이용해서, 각각 한번에 다른 타입의 값을 여러 개의 value에 대입하는 코드입니다.
val (name, age, zipcode) = ("Brandon", 26, "114-2")
println( name )
//> Brandon
println( age )
//> 26
println( zipcode )
//> 114-2
value object 에서 특정 필드만을 추출 해서 일회성으로 사용 할 때에도 유용하겠네요.
val b = Person(1, "Brandon", 26, "114-2", "bra...@gmail.com", -300)
def filter(p: Person): (String, Int) = {
return (p.name, p.age)
}
val res = filter(brandon) //> res = ("Brandon", 26)
다음은 두 수를 입력받고, 몫과 나머지를 리턴하는 함수입니다. (Scala by Example의 예제를 약간 변경했습니다.)
def divmod(x: Int, y: Int): (Int, Int) = {
val a = x / y
val b = x % y
return (a, b)
}
val (q, r) = divmod(100, 7) // res = (14, 2)
println( q )
//> 14
println( r )
//> 7
스칼라에서는 문자열과 숫자를 곱하면 문자열을 횟수만큼 반복합니다.
println("Hello! " * 3) //> Hello! Hello! Hello!
위의 코드를 함수로 만들어 보겠습니다.
def repeter(s: String, c: Int){
println(s * c)
}
위 함수의 파라미터의 타입이 (String, Int)
이므로 웬지 같은 타입의 튜플을 만들어 파라미터로 넘기면 작동 할 것 같습니다.
val t = ("Hello! ", 3)
repeater(t) //> Compile Error!
하지만 컴파일 에러를 뱉어냅니다. 튜플을 파라미터로 직접 전달 할 수 있으면 참 좋을 텐데 말입니다. 만약 튜플을 인자로 받고 싶다면 다음과 같이 함수를 수정해야 합니다.
def repeter2(x: (String, Int)){
println(x._1 * x._2)
}
repeater2(t) //> Hello! Hello! Hello!
작동하긴 하는데, 뭔가 좀 깔끔하지 못하기도 하고… 의도했던 목적대로 사용하기 어렵겠네요. 그래서 다음과 같은 방법이 존재합니다.
def repeter(s: String, c: Int){
println(s * c)
}
def repeater3 = (repeater _).tupled
repeater3(t) //> Hello! Hello! Hello!
(repeater _).tupled3
에 의해 세 개의 파라미터를 가진 함수에서 튜플을 전달 받는 함수로 변환시켜줍니다. 표현법이 좀 생소하지만 아주 요긴하게 사용됩니다.
다음 두 표현은 같습니다.
def repeater3 = (repeater _).tupled
def repeater4 = Function.tupled(repeater _)
마지막으로 하나만 더 보죠,
val x = ("Hello! ", 3)
val y = x match { case (a, b) => a * b} //> y = "Hello! Hello! Hello! "
위와 같은 표현은 _1
, _2
같은 표기법을 사용하지 않으며 가독성을 높이기 위해, 상당히 자주 등장하는 표현입니다. 함수리터럴로 match
를 생략해서 다음과 같이 사용할 수 도 있구요.
tns.map{case (a, b) => a + b} //> List(3, 5, 7)