코틀린 문법(2)
함수
-
기본용어
-프로시저(Procedure) : 반환 값 없는 함수
-엔트리 포인트 함수 : 처음 시작 시 실행되는 함수(=main함수)
-빌트인 함수 : 유용한 기능을 수행하도록 미리 정의한 함수 ( println(), readLine() . . . . .)
함수의 정의
1
2
3
4
5
6
7
8
9
fun sum( num1 : Int , num2 : Int) : Int { return num1+ num2 }
fun test( ) : Unit { println(“반환 값 없음”) return}
// 일반적인 형태는 (이름 , 매개변수 , 반환 자료형 , 함수의 내용)
// 매개 변수가 없다면 void를 여기서는 Unit으로 사용하며 생략해도 된다. return도 생략 가능
// 매개변수는 상수로 값을 가져오기 때문에 값 변경 불가, 새로 변수를 만들어서 바꾸어야 한다.)
함수의 축약
1
2
3
4
5
6
7
8
9
10
fun sum(num1 : Int , num2 : Int) = a+b
((fun sum(num1:Int,num2:Int) : Int { return a+b } ))
fun Bigger(num1 : Int, num2 : Int) = if(num1>num2) num1 else num2
// if의 표현식과 같이 등호(“=”)를 이용해서 반환형태 및 괄호를 생략하고 한 줄로 가독성 향상이 가능
```
함수의 인자 값
1
2
3
4
5
6
7
8
9
10
11
fun test(a:Int = 1, b:Int = 2) { } // a : Int , b : Int = 3 (가급쪽 오른쪽에 몰리게!)
test( )
test(5)
test(b=5)
// C++에서와 같이 디폴트 값 설정 및 임의의 매개변수를 “ : “ 표현으로 직접 대입이 가능하다
// 특별한 이유가 없으면 순서대로 대입되기 때문에 주의해야 한다.
함수의 가변인자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fun test ( vararg manyNums : Int ) : Int {
for ( number in manyNums ) {
//실행 코드
}
}
test(1,2,3,4,5,6) // test(1,2,3) . . .
// 가변적으로 인자를 입력하고 싶다면 “vararg”키워드를 사용
// listOf , arrayOf( ) 함수도 가변인자를 활용해서 만들었다. – 리스트, 집합 객체 만들 때 유용
// Public fun <T> listOf(vararg element : T) : List<T> (예시)
```
전개 연산자
– 배열을 가변인자로 전달
1
2
3
4
5
6
7
8
9
val arr = intArrayOF(1, 2, 3)
var sum3 = TempFunction(_arr)
// Spread연산자 “ _ “ 를 이용해서 배열의 모든 인자를 가변인자로써 사용가능
// 단 arrayOf로 만든 객체는 원시 타입의 배열로 만들어서 사용해야한다
// String의 경우 그냥 사용해도 괜찮다
람다함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
val square : (Int,Int) -> Int = { num : Int, num2 : Int -> num*num2 }
var square = {num:Int,num2:Int -> num * num2} // 두 코드는 같은 내용
val testVoid : ( ) -> Unit = { println(“인자 없음”) }
val testVoid = { println(“인자 없음”) }
// 이름 , 타입 지정(생략 가능) , 인자 값들 , ->반환 값(return)
// 타입이 같은 함수라면 다른 람다 함수를 대입 할 수 있다.
// -int int -> int형태의 +계산기함수를 , 다시 대입해서 -계산기로 바꿀 수 있다는 뜻.
// ex) printHello = { println(“HI”) , printHello = {println(“Not Hi) }
val test : (String -> Unit ) = {println(“Hello $it ) }
val test : (String -> Unit)
test = {name:String -> println(“Hello $name “) } //수정
val test = println(“Hello $it “ ) // ( x ) !!
// 인자 값이 하나라면 it을 이용해 인자 값에 접근 가능 (당연히 직접 명시한 인자 이름도 가능)
// 단 , 함수의 타입을 추론할 수 없게 앞의 타입을 생략했다면 IT사용 불가. 추론이 안되니까..)
함수의 반환값으로 람다함수 반환
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fun makeRamda(uniVal:Char) : (Int,Int)->Int{
when(uniVal) {
('+') -> return { x: Int, y: Int -> x + y }
('-') -> return { x , y -> x-y}
else -> return { x,y -> -1 }
}
}
val calPlus=makeRamda('+')
val calMinus=makeRamda('-')
println(calPlus(1,5))
println(calPlus(2,1)
// “변수 = 람다 함수”를 함수로 구현해서 사용 하는 것.
// 직접 대입해보면 val calPlus=makeRamda(‘+’) == val calPlus = {x :Int, y:Int -> x+y} 와 같음
함수 내 지역변수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fun makeTest() : ()->Unit {
var count = 1
return {
println("함수는 $count 번 출력되었습니다.")
count++
}
}
val test1 = makeTest()
val test2 = makeTest()
println("test1을 두 번 출력합니다.")
test1()
test1()
println("test2를 한 번 출력합니다.")
test2()
println("다시 test1을 한 번 출력합니다(3번째)")
test(1)
함수 내 지역변수 count가 메모리에 남아서 계속 값이 유지된다.
코틀린에서는 바깥 영역의 변수 값을 참조하고 변경하는 작업을 허용한다.
함수의 인자로 람다함수를 전달
1
2
3
4
5
6
7
8
fun temp(var : (Int, Int) -> Int, x: Int , y : Int ) : Int { return var(x,y) }
val result = temp( {x,y -> x+y} , 2, 3 )
// 함수의 인자로 변수가 아니라, 함수의 형태를 선언! (변수의 형태 선언 하듯)
// 함수의 호출에 함수의 값(=람다 함수)을 넣어 직접 함수를 인자로 전달 한다.
함수 참조 연산자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fun sumValue(num : Int, num2:Int) { return num+num2 }
fun minusValue( num :Int, num2:Int ) { return num2-num }
var myTemp : (Int) -> Int = :: sumValue
myTemp = ::minusValue
// 함수도 람다함수와 같이 변수나 상수에 대입 할 수 있다.
fun reverse(s:String) = println(s.reversed( ))
listOf(“Hello”,”World”).forEach( :: reverse ) // olleH \n dlroW 출력.
// 정의한 함수를 “ :: “ 연산자를 통해 지정하여 변수에 대입할 수 있다.
// forEach메서드는 값을 하나씩 함수의 인자값으로 전달하는데 위와 같이 자주 쓰인다.
// 변수에서 타입선언은 생략해도 된다.
// 단 오버로딩된 함수의 경우 모호성이 발생하므로 타입을 꼭 써줘야한다.
// var test = :: println (X) => var test : ( ) -> Unit = ::println
Scope함수
-
let
1 2 3
var temp : String? = “Hello” temp?.let { println(“NULL이 아닐 때 실행합니다.”) }
-
with
1 2 3
var temp : “Hello” var lower = with(temp) { this.toLowerCAse() }
-
run
1 2 3
var p1 = Point(1,2) // 객체 하나 생성 var pointToPair = p1.run { Pair(x,y) } // (2,4)가 반환되서 변수에 저장
-
apply
1 2 3
var p2 = p1.apply { x=100 , y=200 } // 대체로 객체의 내용을 초기화하거나 설정값 적용에 사용됩니다.
-
also
1 2 3 4 5 6
var word = mutableListOf(“Hello” , “World “) words.also { println( $it,first() ) } // 대체로 객체의 값을 변경하지 않고 내용을 조회 할 때 사용됩니다.
Q. 왜 Scope함수를 사용하나요?
가령 임의의 객체값을 설정하고 싶다고 가정해봅시다. 그럴경우
1 2 3 4 Point p1 Point p2 p2.x = p1.x p2.y - p1.y다음과 같이 접근을 할 수 있습니다.
하지만 위와같은 표현식을 사용한다면 임시환경속에서 변수를 만들고 지우고 해도 함수의 지역변수와 같이 일회용 변수를 선언할 수 있습니다.
즉 깔끔한 코드 및 가독성을 높이는데 도움이 됩니다.
댓글남기기