잘 알고 있는 C++/Java의 for 기본 구문 형태는 동일하다.
그러나, 우리는 다수의 변수 생성문을 지정할 수 있다. '<-'를 이용하여 수행되며 이들은 각각 세미콜론으로 구분된다.
[그림 1]
또한 조건 구문을 생성할 수 있다.
[그림 2]
또, 내부에 변수를 추가 생성하여 이용할 수 있다.
[그림 3]
기막히군. 그러나 '산출'(yield) 키워드를 이용하면 '컬렉션'을 리턴한다.
[그림 4]
게다가 첫번째 생성문(?; generator)하고도 같이 호환된다.
[그림 5]
for 내의 변수들인 c나 i는 외부에서 별도로 미리 선언할 필요는 없다.
---------------------------------------------------------------------------------------------
함수.
함수뿐만 아니라 메서드를 갖고 있다. 누가? 스칼라가. (자바는 함수와 유사한 기능을 정적 메서드로 제공했다.)
선언은 다음고 같다.
def abs(x: Double) = if ( x >= 0 ) x else -x
척 보면 척 알수 있다.
def는 함수 선언의 시발점이며 뒤의 abs는 함수명, 뒤는 인자와 타입(':'(콜론)으로 구분)을 적는다.
그리고! '='(대입 기호)를 입력한다. 이것을 중요히 생각해야 한단다.
뒤는 내용이며 즉, 몸체다.
반환형은 문장의 맨 마지막 값이며 이는 블럭과 같다. 고로 return 키워드는 별도로 입력되지 않는다. 그럴 필요도 없다.
(사실 return도 메서드로 되어 있다.)
여기서 반환형의 타입을 지정하는 부분이 없었다. 이는 사실 평상시에는 필요없다. 그래서 필요할 때만 지정하곤 하는데 그 때는 재귀호출을 할 때이다.
def fac(n: Int): Int = if (n <= 0) 1 else n * fac(n - 1)
이와 같이 팩토리얼을 구하는 메서드를 구현할 경우 재귀로 하면 편하다. 이 때 만일 반환 타입 명시를 하지 않으면 실행할 때 반환한 타입이 무엇인지 모르기 때문에 에러가 난다.
':'(콜론)과 타입이 추가되어 입력되면 그것은 반환타입을 명시하는 부분이 된다.
-----------------------------------------------------------------------------------------
디폴트 매개변수.
이런 이런, 자바에 없던 존재가 등장한다.
def decorate(str: String, left: String = "[", right: String = "]") = left + str + right
이를 기준으로 유추가 가능하다. C++이 생각나거나 C#이 생각난다. (사실 알아보는 중에 C#의 문법과 더욱 비슷하다고 느꼈다.)
[그림 6]
이에 별말없이 [그림 6]으로만 대체한다.
---------------------------------------------------------------------------------------------
가변인수
def sum(args: Int*) = {
var result = 0
for (arg <- args) result += arg
result
}
유일하게 보이는 차이점은 파라미터 타입 옆에 바로 존재하는 애스터리스크 문자. 포인터인줄 알았으나 아니다.
val s = sum(1, 4, 9, 16, 25)
이와 같이 가변 길이의 인자를 받는다.
[그림 7]
그런데 리스트 자체를 넘길수는 없다.
[그림 8]
이는 큰 불편이 아닐 수 없지 않을 수 없다.
그래서 이를 해결하기 위해 ':'(콜론)을 통해 부가 설명을 추가한다. '_*'(뭐라 읽어야 해? 한쪽눈만 뜬 인면이모티콘) 키워드를 추가하면 범위값들을 개별 값들로 나누어 함수에 각각 입력해 준다.
[그림 9]
재귀에서도 확장할 수 있다고 하던데,
[그림 A]
-----------------------------------------------------------------------
프로시저
함수에 리턴값이 없는 것을 특별히 부르는 말이다.
def procedures(parameter : String) { // '='가 없어.
...
}
이는
def procedures(parameter : String) : Unit = {
...
}
과 같다.
----------------------------------------------------------------------
게으른 변수(?)
변수의 초기화를 변수 접근이 이루어질 때까지 미루는 경우 이 변수를 지칭하는 이름.
맨 앞에 lazy만 붙인다.
lazy val variable = 123;
만일 변수 variable에 한번도 접근 하지 않는다면 저 변수는 값 할당 전혀 안 받는다. 여기는 예가 좋지 못하지만 인터넷에는 이러한 문장이 있다.
lazy val words = io.Source.fromFile("/usr/share/dict/words").mkString
파일의 모든 단어를 대입하는 구문이라고 했던가.. 저 문장은 실행되기 비싸(?)기 때문에 lazy를 도입했단다.
c"=*B,2*)(&2E*">*7,p$*:,7=90*,0*(,7>A,$*C9)A992 val ,2; def.*!"1#,%9
val words = io.Source.fromFile("/usr/share/dict/words").mkString
// W:,7=,)9;*,0*0""2*,0 words &0*;9>&29;
lazy val words = io.Source.fromFile("/usr/share/dict/words").mkString
// W:,7=,)9;*)(9*>&%0)*)&19 words &0*=09;
def words = io.Source.fromFile("/usr/share/dict/words").mkString
// W:,7=,)9;*9:9%$*)&19 words &0*=09;
------------------------------------------------------------------------------------
예외처리.
throw new IllegalArgumentException(" I am super exception. puhahahaha! ");
이 친구는 Nothing을 리턴한다.
if (x >= 0) sqrt(x)
else throw new IllegalArgumentException("x should not be negative")
에서 x가 음수면 위 문장은 Nothing이 리턴된다.
다른 건 다 필요없다.
try {
process(new FileReader(filename))
} catch {
case _: FileNotFoundException => println(filename + " not found")
case ex: IOException => ex.printStackTrace()
}
이것만 잘 보면 된다.
그렇게 없던 case가 왜 여기서 보이는지... 예외 선택구문이라나... '패턴 매칭'이라던데 지금은 모르겠으나 case 뒤가 패턴 이름인 듯하다. 이름에 선입견은 갖지 말라고 했었다.
try { ... } catch { ... } finally { ... } 도 가능하다.
너무 길었군. 나누기 귀찮았다.
당시 알아냈던 내용 보고를 여기에서 종료한다.
댓글 없음:
댓글 쓰기