데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      [Kotlin] Scope 함수 기본 이해하기 - 01

      KIDO 23.12.27
      2,644 16 1
      DEVOTEE 요약
      코틀린에서는 코드를 간결하게 만들어주는 범위함수(범위지정함수) let, run, with, apply, also 등을 제공한다. 범위함수를 사용하면 객체를 참조하는데 있어 객체의 이름없이 참조가 가능하며, 객체에서 블록 처리를 수행하는 공통된 작업을 수행한다. 하지만 범위함수의 선택은 상황 및 프로젝트의 일관성에 따라 달라지며, 사용방식이나 반환 결과를 기준으로 결정할 수 있다. 범위함수 사용시 필요 사항은 컨텍스트 객체를 참조하는 방법(this와 it의 차이)과 반환값이 다르다는 점, 과도한 사용은 코드를 복잡하게 만들 수 있으니 주의해야한다는 점이다.
      DEVOTEE 추천 블로그

      범위함수


      범위함수 목적

      • 객체의 컨텍스트 내에서 코드 블록을 실행할 수 있도록 해준다.

      • 이를 통해 코드가 간결하게 된다.(객체 참조의 중복 제거)

      • 범위함수를 사용하게 되면 객체 이름없이 객체를 참조 할 수 있게 되어서 범위함수, 범위지정함수 등으로 부른다.

      • 이러한 함수로 let, run, with, apply, also 가 있다.

      • 기본적으로 이 함수들은 모두 동일한 작업(객체에서 블록 처리를 수행)을 수행하게 된다.

      • 차이점은 객체가 블록에서 사용 되는 방식과, 처리 결과가 무엇인지가 달라지는 것이다.


      • 다음과 같은 코드가 있다고 해보자.

      val alice = Person("Alice", 20, "Amsterdam")
      println(alice)
      alice.moveTo("London")
      alice.incrementAge()
      println(alice)
      • 만약 let 범위지정 함수를 사용한다면 다음과 같이 쓸 수 있다.

      Person("Alice", 20, "Amsterdam").let {
        println(it)
        it.moveTo("London")
        it.incrementAge()
        println(it)
      }
      • 위처리를 통해 일기 쉽고 간결한 코드를 작성할 수 있다는 것을 알 수 있다.

      • 샘플 예제 01.sfunction_sample01.kt 파일을 참조하자.

      • 결과는 다음과 같이 둘다 동일할 것이다.

      Name: Alice, Age: 20, Location: Amsterdam
      Name: Alice, Age: 21, Location: London


      범위함수 어떤것을 사용할 것인가?

      • 범위함수는 유사한 처리 결과를 내면서 다양한 함수를 가지고 있으므로 어떤것을 선택해야하는 지는 상황에 따라 다양하며 쉽지 않은 결정일 수 있다.

      • 선택의 기준은 의도와 프로젝트에서 일관성에 따라 다르게 결정될 수 있으며, 다음 표를 통해서 선택의 기준을 잡을 수 있다.

      • 올바른 scope 함수를 목적에 맞게 선택하기 위해서 다음 테이블을 통해 확인할 수 있다.

      Function

      Object reference

      Return value

      확장함수여부

      let

      it

      Lambda result

      Yes

      run

      this

      Lambda result

      Yes

      run

      -

      Lambda result

      No: 컨텍스트 객체 없이 호출되는 경우

      with

      this

      Lambda result

      No: 컨텍스트 객체를 아규먼트로 전달하는 경우

      apply

      this

      Context object

      Yes

      also

      it

      Context object

      Yes

      선택 가이드

      • 널이 될 수 없는 객체에서 lambda를 수행하고자 하는 경우 --> 'let 사용'

      • 로컬 범위 변수로 표현식을 소개하는 경우 --> 'let 사용'

      • 객체 설정 --> 'apply 사용'

      • 객체 설정과 계산 결과 반환시 --> 'run 사용'

      • 표현식이 필요한 명령문 실행 --> '확장하지 않은 run 사용'

      • 추가적인 효과를 필요로 하는경우 --> 'also 사용'

      • 객체에 대한 그룹화 함수 호출 --> 'with 사용'

      • 참고

        • 범위 함수를 사용하면 코드는 간결해지지만, 과하게 사용하면 좋지 않다.

        • 코드를 읽기 어렵게 하고 오류 발생 여지가 있다.

        • 또한 중첩으로 범위함수를 사용하지 않는 것을 추천한다.


      범위 함수를 구별할 수 있는 포인트

      • 대부분 범위 함수는 유사하다.

      • 그러나 차이는 다음과 같다.

        • 컨텍스트 객체를 참조하는 방법이 다르다.

        • 반환값이 다르다.

      컨텍스트 객체 참조

      • 컨텍스트 객체를 참조하는 방법에는 this 와 it가 있다.

      • 범위함수 내부에 전달된 객체는 해당 객체 전체 이름을 사용하는것 보다 간단한 표현식으로 이용하도록 한다.

      • 람다 receiver를 이용할때에는 this를 이용한다.

      • 람다 아규먼트를 이용할때에는 it를 이용한다.

      • 02.sfunction_sample02.kt 파일을 만들고 다음과 같이 작성한다.

      fun main(args: Array<String>) {
        val str = "Hello"
      
        str.run {
          // 아래 두개는 동일하다. 
          println("The string's length: $length")
          println("the string's length: ${this.length}")
        }
      
        println("-------------------------------------")
      
        str.let {
          println("The string's length is ${it.length}")
        }
      }
      • this 이용

        • run, with, apply 는 컨텍스트 객체를 참조할때 lambda receiver 로 이용한다. 이는 this 를 이용하여 참여한다는 의미이다.

        • 대부분의 케이스에서는 this를 생략할 수 있다.

        • 그러나 this를 생략하면 이것이 리시버의 멤버 속성인지, 아니면 외부 객체나 함수를 나타내는지 구별하기 어려울 수 있으니 주의해야한다.

      • it 이용

        • let과 also에서는 컨텍스트 객체를 참조할때 lambda argument 로 이용한다.

        • 아규먼트 이름이 지정되어 있지 않다면 명시적인 기본 이름은 it이다.

      • 아래는 동일한 코드이지만 컨텍스트 객체 참조 방법의 차이를 보여준다.

      fun getRandomInt(): Int {
          return Random.nextInt(100).also {
              writeToLog("getRandomInt() generated value $it")
          }
      }
      
      fun getRandomInt(): Int {
          return Random.nextInt(100).also { value ->
              writeToLog("getRandomInt() generated value $value")
          }
      }
      • 위와 같이 $it 를 이용하는 경우와, 직접 전달 인자($value)를 이용하는 경우가 다름을 알 수 있다.

      반환값

      • 범위함수 반환값이 서로 다르다.

        • apply, also는 컨텍스트 객체를 반환한다.

        • let, run, with 는 람다 결과를 반환한다.

      컨텍스트 객체 반환

      • apply, also 를 이용하면 컨텍스트 객체를 반환한다

      • 즉 컨텍스트 객체를 반환하므로 콜 체인으로 연결할 수 있다.

      • 다음 예제를 통해 numberList를 만들고, also, apply, 다시 also로 체이닝을 걸수 있다.

      • 03.sfunction_sample03.kt 파일을 만들고 다음과 같이 수행해보자.

      fun main(args: Array<String>) {
        val numberList = mutableListOf<Double>()
        numberList.also { println("리스트 생성") }
          .apply { 
            add(3.14)
            add(1.0)
            add(80.0)
           }
           .also { println("다음으로 소트 수행") }
           .sort()
        println("최종결과: " + numberList)
      }
      • 실행 결과는 다음과 같다.

      리스트 생성
      다음으로 소트 수행
      최종결과: [1.0, 3.14, 80.0]

      람다 결과 반환

      • let, run, with 는 람다 결과를 반환한다.

      • 그러므로 이를 이용해서 결과값을 할당하거나, 결과에 대한 변경을 수행할 수 있다.

      • 04_sfunction_sample04.kt 파일을 만들고 다음과 같이 작성하자.

      fun main(args: Array<String>) {
        val numbers = mutableListOf("one", "two", "three")
        val countEndsWithE = numbers.run {
          add("four")
          add("five")
          count { it.endsWith("e") }
        }
      
        println("e로 끝나는 단어의 총 개수는 $countEndsWithE 개 입니다.")
      }
      • 위와 같이 run 범위함수를 이용하여 'e' 로 끝나는 단어를 세어 결과로 반환한다.

      • 결과는 다음과 같다.

      e로 끝나는 단어의 총 개수는 3 개 입니다.
      • 물론 결과를 반환하지 않고도 범위함수를 사용할 수 있다.

      • 05_sfunction_sample05.kt 파일을 만들고 다음을 수행해보자.

      fun main(args: Array<String>) {
        val numbers = mutableListOf("one", "two", "three")
        with(numbers) {
          val firstItem = first()
          val lastItem = last()
          println("First Item is : $firstItem, Last Item is : $lastItem")
        }
      }
      • 결과는 다음과 같다.

      First Item is : one, Last Item is : three


      WrapUp

      • 지금까지 let, run, with, apply. also 등과 같은 범위 함수에 대해서 알아 보았다.

      • 범위 함수는 처리 내용은 대부분 비슷하지만, 리시버를 무멋으로 참조하느냐 (this, it) 와 반환값이 무엇이냐 (객채 참조, 람다결과) 를 이용하여 어떤것을 선택하지 결정된다는 것도 확인했다.

      • 다음으로 범위 함수에 대해서 하나하나 알아보면서 사용예를 알아볼 것이다.

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      KIDO 님의 최신 블로그

      더보기

      DEVOTEE 추천 블로그

      동영상 기고하기