Kotlin에서 자주 잊혀지는 기능

18176 단어 kotlin
이번에는 Kotlin의 일부 기능을 살펴보겠습니다. 이 기능들은walktroughs나 다른 곳에서 자주 무시되지만, 여전히 멋있고 유용할 수 있습니다.어떤 사람들은 우리 중 일부는 알 수 있지만, 왕왕 존재하는 특징을 잊어버린다.그리고 일부 기능은 우리가 그것들이 언급되기 전에 존재하는 것을 잊어버린 것이다. 아마도 우리가 그것들을 자주 사용하지 않았기 때문일 것이다.당신이 이미 존재를 잊어버린 최소한의 기능을 볼 수 있기를 바랍니다!

내연 대상


Kotlin에서 내연/익명 대상이 가장 잘 알려진 용법은 인터페이스를 실현하는 대상을 보내야 한다는 것이다. (자바의 의미에서) 특정한 대상이 코드에서 한 번만 있으면 lambda가 부족하다. (인터페이스가 작동하지 않기 때문에 몇 가지 방법이 있기 때문이다.)만약 네가 이전에 본 적이 없다면, 이것은 좀 곤혹스러울 것이다.이러한 좋은 예를 찾기는 매우 어렵다. 왜냐하면 이런 상황은 자주 발생하지 않기 때문이다. (클릭 처리 프로그램이 있는 안드로이드에서 더 많이 발생할 수 있기 때문이다.)Runnable을 간단한 예로 들겠습니다. 비록 쉽게 lambda를 사용할 수 있지만.
  val myThread = Thread(object : Runnable {
      override fun run() {
          println("Using an anonymous inner class/object")
      }
  })
지금 당신은 이것이 어떻게 잊혀진 기능이냐고 물어볼 수 있습니다.이것은 결코 보기 드문 현상이 아니다!네 말이 맞다. 이것이 바로 내가 이 절에서 가장 유명한... 으로 시작하는 이유다.현재 우리가 자주 잊어버리는 기능은 가능하다.실제로 JavaScript에서 사용하는 것처럼 객체에 대한 변수만 만들 수 있습니다!
      val myObj = object {
          val name = "somename"
          val pair = getRandomPoint()
          val somelist = listOf("Element", "Another element")
      }

      println(myObj.name)
      println(myObj.pair)
      println(myObj.somelist)
함수도 있지만 인터페이스를 실현하지 않으면 대상 외부에서 볼 수 없습니다.이 규칙의 예외는 Any 클래스에서 찾을 수 있는 방법이며, 내부 연결/익명 대상 (예: toString) 에서 다시 쓸 수도 있습니다.또 다른 제한이 있다.특이하고 우울한 문제는 위의 쌍을 분해하고 요소에 접근할 수 없다는 것이다.
  val myObj = object {
      val (x,y) = getRandomPoint()
  }

  // NOT ALLOWED! :( 
  println(myObj.x)
  println(myObj.y)
이는 Kotlin의 향후 버전에서 수정될 수 있습니다.또한 파일의 최상위 수준에서 인라인 객체를 사용할 수 없으며 함수나 클래스에서 사용해야 합니다.적어도 KScript를 사용하여 스크립트를 작성한 경험에 따라 다릅니다.
지금 당신은 마지막 기능이 어디에서 유용하냐고 물어볼 수 있습니다.이것은 클래스의 개인적인 방법에서 되돌아오는 값으로 사용하거나 변수 그룹을 나누는 작업 저장소로 사용할 수 있습니다.일반적으로 우리는 더 큰 프로젝트에서 이런 방법을 사용하는 것을 피해야 한다고 생각한다. 왜냐하면 프로젝트가 발전함에 따라 가독성을 방해할 수 있기 때문이다.다른 한편, Kotlin의 스크립트에 대해, 나는 코드를 간결하게 유지하고 논리적 그룹을 만드는 것이 매우 유용하다고 생각한다.이것이 바로 내가 생각하는 그것의 가장 큰 용도이다.

테일러크


우리는 계승의 가장 간단한 귀속 실현부터 시작한다.
  fun factorial(n : Int) : Int {
      if(n <= 0) {
          return 1
      }

      return n*factorial(n-1)
  }
귀속 호출이 완료될 때마다 더 많은 메모리를 소모하는 변수 값을 포함하는 새 창고 페이지를 만들 수 있다는 것을 기억하십시오. (여기는 새로운 n 값)위의 실현에서 우리는 n의 값에 따라 많은 새로운 창고 페이지가 있을 것을 보았다. 우리는 호출이 끝난 후에 거슬러 올라가 (즉if검사에서 기본적인 상황에 도달하는 것) 곱셈을 계산해야 한다.
우리는 어떻게 개선합니까?꼬리 부분의 귀속 개념을 사용하다.무엇이 끝부분의 귀속입니까?끝부분 귀속은 컴파일러 최적화(또는 Scheme, 해석기 최적화 등 다른 언어에서)로 매번 창고 페이지를 다시 사용해서 고전적인 귀속 함수에 필요한 귀속을 피해야 한다.이러한 조건이 충족되면 더 이상 귀속 과정이 아니라 교체 과정이다(일반적인 순환과 같다).듣기 좋죠?너는 거슬러 올라갈 필요가 없는 방식으로 함수를 작성해야만 일을 할 수 있기 때문에 많은 책임이 너에게 있다.이런 식으로 함수를 작성하면tailrec 키워드를 사용할 수 있습니다.이러한 방법으로 계승을 실현하는 방법은 기본값이 있는 선택할 수 있는 매개 변수를 사용하는 것이다. (문서에 그것이 어떻게 작동하는지, 특히 다른 사람이 사용할 수 있다면.)
    tailrec fun factorial(n : Int, sum : Int = 1) : Int {
        if(n <= 0) {
            return sum
        }

        return factorial(n-1, sum*n)
    }
이것은 단지 가능한 방법일 뿐이니, 너는 더욱 좋은 해결 방법을 찾을 수 있을 것이다.
궁금하실 수도 있어요.만약 내가 상술한 조건을 만족시키지 못한 상황에서tailrec 키워드를 사용한다면 마지막 호출은 끝부분 호출(즉, 거슬러 올라갈 필요가 없음)이다.컴파일러가 귀속 호출이 끝부분 호출이 아니라는 경고를 받을 것이다. 이렇게 간단하다.

lambdas의 확장 함수


lambda는 배후 클래스의 실례입니다. 이것은 확장 함수를 만들 수 있음을 의미합니다.만약 네가 생각해 본 적이 없다면, 이것은 사람을 곤혹스럽게 할 수도 있다.유명은 어떤 것입니까?lambda를 만들고 확장 함수를 만듭니다.우선 간단한dd 함수입니다.
  val add : (Int,Int) -> (Int) = { num1,num2 ->
      num1 + num2
  }
dd 함수의 유형을 자세히 보십시오.이것이 바로 우리가 그것을 위해 확장 함수를 만들 수 있는 클래스입니다!같은 함수를 반환하는 새 확장 함수를 만들지만 간단한 print 문에서 시작합니다.
  fun ((Int,Int) -> (Int)).logged() : ((Int,Int) -> (Int)) {
      return { num1,num2 ->
          println("Calling function ${this.toString()}")
          this(num1,num2)
      }
  }
현재 우리는 그것이 사용 중인 것을 볼 수 있다.
var addLogged = add.logged()
println("2+3 = ${addLogged(2,3)}")
예상한 대로 출력은 다음과 같습니다.
  Calling function (kotlin.Int, kotlin.Int) -> kotlin.Int
  2+3 = 5
이것은 매우 간단한 예이다. 너는 이 기능으로 더 많은 재미있는 일을 할 수 있다.아마도 당신은 기억판의 함수를 만들고 싶습니까?또는 함수의 조합을 만들거나(예를 들어 두 함수 f와 g를 위해 a=f(g(x))=함수를 만들거나)?특히 함수식 프로그래밍 분야를 둘러보면 더 재미있는 용례를 발견할 수 있을 것이다.

속성/변수 위임


교실 라이센스 개요


대다수의 사람들이 학급 등급의 권한을 알고 있지만, 만약 당신이 모른다면, 우리는 빠르게 되돌아봅시다.하나의 종류를 확장하거나 인터페이스를 실현할 때 이런 관계는'isa'유형에 속한다(예를 들어 도요타는 자동차이고 시베리아 하스키는 개 등).조합은 관계를 변수에 저장한다. 유형은'hasa'(예를 들어 매니저 관리/프로그래머가 그들을 위해 일하게 하고 고양이가 그들에게 음식을 주는 등)이다.위임은 작문의 특수한 상황으로 우리는 숙제를 다른 반에 위임한다.너는 너의 고양이가 인간 인터페이스를 실현하게 하고 싶지 않을지도 몰라. 단지 음식을 얻기 위해서...?너는 고양이의 하인/주인에게 일을 맡기고 싶다.이것은 코틀린에서 보기에 어떻습니까?
  interface Human {
      // usually the implementation would be implementation specific
      fun getFood() {
          println("Getting food")
      }
  }
  // implementations that in the real world probably implements their own getFood
  class GrownUp : Human

  class Cat(val name : String, servant : Human) : Human by servant


  // usage
  val me = GrownUp()
  val myCat = Cat("Mittens", me)
  myCat.getFood()
고양이가 인간 인터페이스를 실현한 것처럼 보이지만 막후에서 일을 맡겼다.이것이 바로 이런 의뢰의 힘이자 왜 그것이 자주 특수한 조합 형식이라고 불리는가이다. (왜냐하면 그의 용법은 기본적인 조합과 약간 다르기 때문이다.)
주의!나는 단지 분명히 말하고 싶었을 뿐이다.위의 예는 매우 간단해서 이 점을 설명할 수 있다.만약 네가 여전히 확실하지 않다면, 더 많은 예를 보고 싶다면, 나는 건의한다.요점만 준비하라고 한 거니까 복습만 하면 될 것 같아:)

정부 문서를 조사하다. 속성/변수


위의 대표단 예시들은 많은 Kotlin 텍스트에 명확하게 소개되어 있기 때문에 귀하께 익숙할 것입니다.당신도 속성/변수에 의뢰를 사용할 수 있다는 것을 아십니까?이것은 주어진 유형을 둘러싸고 추가 기능을 추가하는 간단한 방법이다.만약 네가 숫자가 있는 변수를 원한다면, 그것은 짝수일 뿐이다.또는 소문자 문자열만 가능합니다.이런 어리석은 예가 어떻게 실현되었는지 살펴보자.
  // Even number
  class EvenNumber(private var num : Int) {
      operator fun getValue(thisRef : Any?, prop : KProperty<*>) : Int {
          return num
      }

      operator fun setValue(thisRef: Any?, prop : KProperty<*>, newValue : Int) {
          if(newValue % 2 == 0) {
              num = newValue
          } else {
              num = newValue - 1
          }
      }
  }

  var evenNum : Int by EvenNumber(23)
  println(evenNum)
  evenNum = 11
  println(evenNum)
  evenNum = 2
  println(evenNum)

  // string always lower case
  class LowerCaseString(private var str : String) {
      operator fun getValue(thisRef : Any?, prop : KProperty<*>) : String {
          return str
      }

      operator fun setValue(thisRef: Any?, prop : KProperty<*>, newValue : String) {
          str = newValue.lowercase()
      }
  }

  var myStr : String by LowerCaseString("Hello there")
  println(myStr)
  myStr = "hi"
  println(myStr)
  myStr = "MY HANDS ARE TYPING WORDS"
  println(myStr)
에이전트는 인터페이스를 실현할 필요가 없지만, 상술한 방법을 실현해야 한다는 것을 알 수 있습니다. (값/VAL은 setter가 필요하지 않을 수도 있습니다.)
이제 출력이 어떻게 되는지 봅시다.
  23
  10
  2
  Hello there
  hi
  my hands are typing words
주의!구조 함수에 setValue가 호출되지 않았음을 알 수 있습니다. 이것은 제가 조심하길 바랍니다.만약 이 점에서 그것을 실행하고 싶다면, 현식 구조 함수나 init 블록을 사용하는 것을 권장합니다.
이 예들은 일부러 좀 어리석지만, 그것들을 대표하여 간단한 검증 용례를 보여 주었다.이제 그들이 어떻게 일을 하는지 알게 되면 더 많은 재미있는 것을 생각해 낼 수 있을 것이다.)

영예상


=== 사용


만약 equals 방법을 실현했다면, 구조가 같은지 확인합니다. (예를 들어 필드가 서로 같습니다.)동일한 대상인지 확인하려면 equals 방법을 삭제해야 합니까?아니요!===을 사용하도록 변경하고 객체가 메모리에 있는 동일한 객체(즉, 동일한 참조)인지 확인할 수 있습니다.

좋은 웹페이지 즐겨찾기