스코프함수 이해를 위한 고차함수, 람다

don9wan·2021년 9월 15일
0

Kotlin

목록 보기
2/3
post-thumbnail

스코프 함수를 이해하기 위해 고차함수, 람다에 대해 알아보자

고차함수

  • 정의
    • 함수를
    • 인자로 전달하는 || 결과로 반환하는
    • 함수가 고차함수이다.

  • 함수가 인자면, 함수의 자료형은 어떻게 생겼나?
    • (parameters) -> returnType
    • 예를 들면
    • (int, int) -> int
      • 함수의 파라미터 : Int, Int
      • 함수의 리턴값 : Int
    • () -> Unit
      • 함수의 파라미터 : x
      • 함수의 리턴값 : x

고차함수 코드

1 fun 더하기_함수(a : Int, b : Int){ return (a + b); }

2 fun 3곱하기_고차함수(func : (Int, Int) -> Int){
	print( func(1, 2) * 3 )
}

3 <<main>>
  3곱하기_고차함수(::더하기_함수)

4 <<출력>>
  9
  • 어떤 코드인가

    1. 흔한 덧셈 함수
    2. 인자로 받은 (Int, Int) -> Int 함수에 1, 2를 넣은 결과값 * 3 값을 출력하는 고차함수 작성
    3. main : 고차함수에선, 인자로 전달하는 함수 앞에 콜론 두개를 붙여 전달해야 함
    4. 더하기 함수의 리턴값인 (1+2)에 고차함수의 3이 곱해진 결과 9가 출력

  • 생소한 함수 자료형

    • 위에서 Kotlin의 함수는 일급 객체라고 설명했고, 함수도 클래스처럼 인스턴스화될 수 있다고 설명했다.

    • 우리는 이제 함수의 자료형이 어떻게 생겼는지 안다.

    • 함수를 인스턴스화하여 변수에 저장해보자

    • var 더하기_함수 : (Int, Int) -> Int = ::더하기_함수```
      
    • 그런데, 인자로 넘길 함수를 굳이 이름까지 붙여 따로 만들 필요가 있을까?

    • "람다함수의 등장"




람다함수

말그대로 함수의 이름을 작성하지도, 따로 만들지도 않겠다는 것이다.

필요한 곳에서 즉시, '함수의 파라미터, 내용'만 작성하여 사용한다.
이 때 작성한 함수가 바로 람다함수이다.

fun sum(a : Int, b : Int) : Int { return a + b }
{ a : Int, b : Int -> a + b }	//위의 함수를 람다식으로 작성

람다식을 적용한 고차함수 코드

//더하기_함수가 사라졌다!

fun 3곱하기_고차함수(func : (Int, Int) -> Int){
	print( func(1, 2) * 3 )
}

<<main>>
3곱하기_고차함수( {a, b -> a + b} )	  //람다식의 마지막 줄(a+b)이 람다식의 반환값이다.

<<출력>>
9
  • 왜 람다를 쓰는가?
    • 이름도 없고, 함수를 따로 작성하지 않아도 된다.
    • 편리하고, 코드 가독성을 높여줄 '수' 있기 때문에 쓰는 것이 맞다.
    • 하지만 람다는 양날의 검이다.
  • 단점
    • 함수 내에 이름도 없이 위치하기 때문에, 에러 발생 시 발생 지점을 찾기 어려워질 수 있다.
    • 작성했던 람다식 코드를 재사용하지 않을 것이라 확신하기 어렵다.
      • 개발자에게 코드 중복이란?
      • 함수를 작성하는 가장 큰 이유 중 하나가, 코드 재반복을 하지 않기 위해서이다.
    • 람다식이 길면 오히려 코드 가독성을 저해할 수 있다.
  • 언제 써야 좋은가
    • 해당 함수를 재사용하지 않는다는 확신이 들 때
    • 함수식이 비교적 간단할 때




안드로이드에서의 '고차함수 + 람다'

Android Studio에서 코틀린으로 개발을 해봤던 사람이라면, 고차함수와 람다식 형태를 봤던 적이 아마도 있을 것이다. Button의 클릭 이벤트를 처리하는 경우 고차함수+람다의 형태를 가진다.

람다를 사용하지 않고 ClickListener 구현

button1.setOnClickListener( View.OnClickListener() {
	override fun onClick(view : View!){
		//클릭 이벤트 처리 내용
})
  • 코드
    • setOnCLickListener() : 버튼에 클릭 이벤트 리스너를 추가하는 함수
    • View.OnClickListener() : View가 클릭될 때 호출되는 콜백에 대한 이벤트 핸들러 인터페이스
    • onClick(View view) : 콜백 메소드 (이벤트 처리 함수)
      • Called when a view has been clicked.
    • 위 버튼 이벤트 처리 코드에서, 추상메소드 onClick()을 구현한 이벤트 핸들러 인터페이스 객체 'onClickListener()'를 전달하고 있다.
  • 왜 인터페이스를 전달했나
    • Java 8 ver.에서 람다를 발표하기 이전에는 함수를 인자로 전달하기 위해, 해당 함수가 선언된 인터페이스를 구현한 클래스를 정의하고 객체를 생성하여, 그 객체를 매개변수로 전달하는 방법을 주로 사용했다.

람다를 사용해 ClickListener 구현

button1.SetOntClickListener{ v ->		
	//클릭 이벤트 처리 내용
}

코드가 비약적으로 줄어들었다. 코드를 살펴보자.

  • View.OnClickListener()는 어디로 갔나요?

    SAM(Single Abstract Method) 변환

    • 함수가 하나뿐인 자바의 인터페이스나 클래스의 익명객체를 람다식으로 표현 가능합니다.
    • 단, Java에서 작성한 Interface 정의와 이를 활용하는 setOnClickListener를 kotlin에서 부르는 경우에만 SAM이 동작합니다.
    • View.OnClickListener는 원래 자바의 인터페이스이고 가지고 있는 구현 메소드가 한개(onClick) 뿐이므로 익명객체로 생성 및, 구현 메소드 onClick()을 손쉽게 구현 받아 람다식으로 표현하는 것이 가능하다.

        button1.setOnClickListener({ v ->
        //클릭 이벤트 처리 내용
      })
    • 이 때 v는 onClick(view : View!)의 파라미터 view를 의미한다.

      • 파라미터가 하나이므로 파라미터를 적지않고 it으로 사용이 가능하다.
  • 소괄호는.. 어디 갔나요?

    • 먼저, Kotlin은 함수에 전달하는 마지막 인자가 함수일 때만 소괄호를 밖에 바로 람다식 코드를 쓸 수 있다.
    • 또한, setOnClickListener()는 인자가 하나 뿐이므로 소괄호 생략이 가능하다.

p.s : 선택적 수용을 지향합니다. 오류가 있을 수 있습니다.

profile
한 눈에 보기 : https://velog.io/@dongwan999/LIST

0개의 댓글