Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

스칼라의 Type에 대해서

스칼라는 정적타이핑이지만 타입추론을 제공하고 있기 때문에 타입에 대해서 많은 정보를 명시하지 않아도 됩니다.(추론은 컴파일타임때 일어납니다.)

정적타이핑은 2가지 이점이 있습니다.
  1. 컴파일 타입체크는 컴파일된 코드가 예상대로 동작한다는 것을 신뢰할 수 있습니다.
  2. 컴파일러 인증포맷에서 API를 기대대로 표현할 수 있습니다.

var num: Int = 10 // 타입 명시함
// num: Int = 10
var num2 = 10 // 타입 추론 사용
// num2: Int = 10
var str = "Ousider" // 타입 추론함
// str: java.lang.String = "Outsider"

import할 때 java.util._는 자바에서 java.util.*과 동일합니다. 언더스코어(_)가 팩키지 이름이 아닌 클래스이름뒤에 오면 자바의 static import와 동일합니다.



타입

Scala의 Type Diagram

출처 : http://programming-scala.labs.oreilly.com/ch07.html#scalas-type-hierarchy

스칼라에서 타입의 구조는 위와 같으며 Any, Nothing, Option이라는 특별한 타입을 제공하고 있습니다.
Any 타입은 모든 타입의 superclass이기 때문에 어떤 타입의 오브젝트도 참조할 수 있는 추상클래스입니다.
AnyVal, AnyRef는 Any의 자식으로 AnyVal은 Int, Double 같은 Java의 primitive타입과 매핑되는 타입들의 기본이 되고 AnyRef는 모든 레퍼런스 타입의 기본이 됩니다. AnyRef는 바로 자바의 Object에 매핑됩니다.
Nothin타입은 모든 타입의 최하위 타입니다. 정해진 타입외에 exception을 리턴하게 되면 Nothing타입으로 추론합니다.
Option[T]타입은 결과가 정해지지 않은 경우를 위해서 지원합니다. 상황에 따라 Option[T]를 상속받은 Some[T]나 None을 리턴할 수 있으며 이는 NullPointerException을 줄일 수 있게 해줍니다.

new ArrayList는 타입을 Nothing로 추론하기 때문에 ArrayList[Int]처럼 제너릭을 지정한 ArrayList를 할당하려고 하면 컴파일 오류가 발생합니다.


import java.util._
var a:Int = 10
var b:Any = null
b = a

Any는 최상위이기 때문에 위 코드와 같은 할당은 허용합니다.




메서드 리턴타입 추론
메서드의 리턴타입에 대한 추론은 메서드를 정의하는 방법에 따라 달라지는데 메서드를 등호(=)로 정의한다면 스칼라는 리턴타입을 추론하고 없다면 void가 됩니다. 일반적으로는 타입추론을 사용하도록 등호(=)의 사용을 권장합니다.


def method1() { 6 } // 리턴타입 void
def method2() = { 6 } // 리턴타입 Int
def method3() = 6 // 리턴타입 Int
def method4 : Double = 6 // 리턴타입 Double

메서드를 정의할때 바디가 한문장이면 {}를 사용안할 수 있습니다.




가변적인 아규먼트(Varargs -  Variable Arguments)의 전달
메서드의 파라미터에 대해서는 (param: Int)처럼 이름과 타입을 모두 명시에 주어야 하는데 (param: Int*)처럼 스타(*)를 사용해서 가변적인 갯수의 파라미터를 여러개 받을수 있으며 이를 Varargs(Variable Arguments)라고 하는데 이는 array로 간주하기 때문에 이터레이트를 사용할 수 있습니다.




파라미터화 된 타입의 변화
서브클래스인스턴스의 컬렉션을 상위클래스의 컬렉션으로 보내는 것을 covariance라고 하고 그 반대인 슈퍼클래스 인스턴스의 컬렉션을 서브클래스의 컬렉션으로 보내는 것을 contravariance라고 합니다.


class Flower() {}
class Rose() extends Flower() {}
def addFlower(flower: Array[Flower])
val r = Array(new Rose())
addFlower(r)

위코드에서 5번째 줄에서 컴파일타임때 오류가 발생하는데 이는 서브클래스를 상위클래스처럼 다룰 수 없기 때문입니다. def addFlower[T <: Flower](flower: Array[T]) {} 처럼 메서드를 정을할때 [T <: Flower]을 사용해서 T가 Flower의 자손클래스라는 것을 명시해 줄수 있고 이렇게 작성하면 위의 오류가 해결됩니다. 아니면 클래스를 선언할때 class Test[+T]라고 작성하면 covariance를 허락하고 contravariance를 사용하려면 [-T]를 사용하면 됩니다.
2010/06/01 01:52 2010/06/01 01:52