코 틀린의 통합 키워드는 어떻게 작동합니까?


144

나는 reified키워드 의 목적을 이해하려고 노력하고 있으며 , 그것은 generics에 대한 반영을 가능하게합니다 .

그러나 내가 그것을 떠나면 그것은 잘 작동합니다. 언제 이것이 실제적인 차이를 만들지 설명 할 사람이 있습니까?


반사가 무엇인지 알고 있습니까? 또한 유형 삭제에 대해 들었습니까?
Mibac

3
제네릭 형식 매개 변수는 런타임에 지워집니다. 아직 지워지지 않은 경우 형식 지우기에 대해 읽으십시오. 인라인 함수의 수정 된 유형 매개 변수는 메소드 본문을 인라인 할뿐만 아니라 일반 유형 매개 변수 (T :: class.java와 같은 작업을 수행 할 수 있음) (일반 일반 유형으로는 수행 할 수 없음) 지금 정답을 살릴 시간이 없어서 의견을 말하고 있습니다.
F. George

리플렉션에 의존하지 않고 유형을 인수로 전달하지 않고도 구체적인 일반 유형의 함수에 액세스 할 수 있습니다.
BladeCoder

답변:


368

TL; DR : reified좋은 점

fun <T> myGenericFun(c: Class<T>) 

와 같은 일반 함수의 본문에서는 컴파일 타임에만 사용할 수 있지만 런타임에 지워 지기 때문에 myGenericFun유형에 액세스 할 수 없습니다 . 따라서 함수 본문에서 일반 유형을 일반 클래스로 사용하려면에 표시된대로 클래스를 매개 변수명시 적으로 전달 해야합니다 .TmyGenericFun

그래도 reifiedinline함수 를 작성하면 런타임에도 유형에 액세스 할 수 있으므로 추가 로 전달할 필요가 없습니다 . 마치 일반 클래스 인 것처럼 작업 할 수 있습니다 . 예를 들어 변수가의 인스턴스 인지 확인하고 싶을 때 쉽게 수행 할 수 있습니다 . TTClass<T>T TmyVar is T

이러한 유형 의 inline함수 는 다음과 같습니다.reifiedT

inline fun <reified T> myGenericFun()

어떻게 reified작동

함수reified 와 함께 만 사용할 수 있습니다 . 이러한 함수는 컴파일러 가 함수의 바이트 코드 를 함수가 사용되는 모든 위치에 복사합니다 (함수가 "인라인"되어 있습니다). Refined Type으로 인라인 함수를 호출하면 컴파일러는 형식 인수로 사용 된 실제 형식을 알고 해당 클래스를 직접 사용하도록 생성 된 바이트 코드를 수정합니다. 같은 따라서 호출 된다 (유형 인수가 있다면 ) 바이트 코드와 런타임에.inlinemyVar is TmyVar is StringString


얼마나 도움 reified이 될 수 있는지 보여주는 예를 살펴 보겠습니다 . 우리는 대한 확장 기능을 만들 String라고 toKotlinObject시도는 함수의 제네릭 형식에 의해 지정된 유형으로 일반 코 틀린 객체에 JSON 문자열을 변환 할 수 있음 T. com.fasterxml.jackson.module.kotlin이를 위해 사용할 수 있으며 첫 번째 접근 방식은 다음과 같습니다.

a) 형식이없는 첫 번째 방법

fun <T> String.toKotlinObject(): T {
      val mapper = jacksonObjectMapper()
                                                        //does not compile!
      return mapper.readValue(this, T::class.java)
}

그만큼 readValue 메소드는 구문 분석해야하는 유형을 사용합니다 JsonObject. Classtype 매개 변수 를 얻으려고 T하면 컴파일러에서 " 'T'를 고정 형식 매개 변수로 사용할 수 없습니다. 대신 클래스를 사용하십시오."

b) 명시 적 Class매개 변수를 사용한 해결 방법

fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
    val mapper = jacksonObjectMapper()
    return mapper.readValue(this, c.java)
}

해결 방법으로 Class of T를 메서드 매개 변수로 만들 수 있으며이 매개 변수는에 대한 인수로 사용됩니다 readValue. 이것은 작동하며 일반적인 Java 코드에서 일반적인 패턴입니다. 다음과 같이 호출 할 수 있습니다.

data class MyJsonType(val name: String)

val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)

c) 코 틀린 방식 : reified

유형 매개 변수 inline와 함께 함수 사용reifiedT 다르게 구현할 수 있습니다.

inline fun <reified T: Any> String.toKotlinObject(): T {
    val mapper = jacksonObjectMapper()
    return mapper.readValue(this, T::class.java)
}

테이크 할 필요가 없습니다 ClassT추가는,T 일반 수업처럼 사용할 수 있습니다. 클라이언트의 경우 코드는 다음과 같습니다.

json.toKotlinObject<MyJsonType>()

중요 사항 : Java를 사용한 작업

reified유형이 인라인 된 함수 는 Java 코드 에서 호출 할 수 없습니다 .


6
귀하의 포괄적 인 답변에 감사드립니다! 실제로 말이됩니다. 내가 궁금해하는 한 가지 기능이 어쨌든 함수가 인라인되는 경우 왜 통일이 필요한가? 어쨌든 유형 삭제를 유지하고 기능을 인라인합니까? 함수를 인라인하면 사용중인 유형을 인라인 할 수 있습니까? 아니면 여기에 잘못된 것이 있습니까?
hl3mukkel

6
귀하의 의견에 감사드립니다. 실제로 답변을 줄 수있는 것을 언급하는 것을 잊어 버렸습니다. 일반 인라인 함수는 Java 에서 호출 할 수 있지만 유형 매개 변수가있는 함수는 할 수 없습니다! 이것이 인라인 함수의 모든 유형 매개 변수가 자동으로 수정되지 않는 이유라고 생각합니다.
s1m0nw1

함수가 구체화 매개 변수와 비 화재 매개 변수를 혼합하면 어떻게됩니까? 어쨌든 Java에서 호출 할 수없는 경우 모든 유형 매개 변수를 자동으로 수정하지 않는 이유는 무엇입니까? kotlin이 모든 유형 매개 변수에 대해 명시 적으로 구체화해야하는 이유는 무엇입니까?
Vairavan

1
스택의 상위 호출자가 json.toKotlinObject <MyJsonType> ()이 아니라 다른 객체에 대해 json.toKotlinObject <T> ()가 필요하지 않은 경우 어떻게해야합니까?
7

1

단순한

* 컴파일 시점에 사용 권한을 부여하는 것입니다 (함수 내부의 T에 액세스하기 위해)

예 :

 inline fun <reified T:Any>  String.convertToObject(): T{

    val gson = Gson()

    return gson.fromJson(this,T::class.java)

}

같은 사용 :

val jsonStringResponse = "{"name":"bruno" , "age":"14" , "world":"mars"}"
val userObject = jsonStringResponse.convertToObject<User>()
  println(user.name)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.