Kotlin에서 "수신자"는 무엇입니까?
확장 기능과 어떤 관련이 있습니까? with
함수 가 키워드가 아닌 이유는 무엇 입니까?
이 주제에 대한 명시적인 문서는 없으며 확장 에 대한 지식의 가정 만있는 것 같습니다 .
수신기의 개념에 대한 기존 문서가 거의없는 것 같습니다 ( 확장 함수와 관련된 작은 참고 사항 만 있음 ).
- 그들의 존재는 확장 기능에서 튀어 나온다 .
- 상기 확장 기능을 사용하여 DSL 을 구축하는 역할 ;
- 수신자에 대한 지식이없는 경우 표준 라이브러리 함수 의 존재
with
는 키워드 처럼 보일 수 있습니다 . - 함수 유형에 대한 완전히 분리 된 구문 .
이 모든 주제에는 문서가 있지만 수신자에 대한 자세한 내용은 없습니다.
먼저:
수신기 란 무엇입니까?
Kotlin의 모든 코드 블록은 수신기 로 유형 (또는 여러 가지)을 가질 수 있으므로 자격을 부여하지 않고도 해당 코드 블록에서 수신기의 함수와 속성을 사용할 수 있습니다.
다음과 같은 코드 블록을 상상해보십시오.
{ toLong() }
별로 말이 안되죠? 실제로 이것을 함수 유형 에 할당하면 (Int) -> Long
-여기서는 Int
(유일한) 매개 변수이고 반환 유형은 Long
-컴파일 오류가 발생합니다. 암시 적 단일 매개 변수를 사용하여 함수 호출을 한정하여이 문제를 해결할 수 있습니다 it
. 그러나 DSL 구축의 경우 다음과 같은 문제가 발생합니다.
- DSL의 중첩 된 블록은 상위 레이어를 섀도 잉합니다.
html { it.body { // how to access extensions of html here? } ... }
이것은 HTML DSL에 문제를 일으키지 않을 수 있지만 다른 사용 사례에서는 발생할 수 있습니다. it
특히 매개 변수 (곧 수신자가 될)를 많이 사용하는 람다의 경우 호출로 코드 를 흩 뜨릴 수 있습니다.
이것은 수신기 가 작동하는 곳 입니다.
갖는 기능 타입 코드 블록을 할당하여 Int
A와 수신기 (!하지 파라미터 등), 코드는 컴파일 갑자기 :
val intToLong: Int.() -> Long = { toLong() }
여기서 무슨 일이야?
약간의 사이드 노트
이 항목에서는 함수 유형에 익숙하다고 가정 하지만 수신기에 대한 약간의 추가 참고 사항이 필요합니다.
함수 유형은 유형과 점을 접두사로 지정하여 하나의 수신자를 가질 수도 있습니다 . 예 :
Int.() -> Long // taking an integer as receiver producing a long
String.(Long) -> String // taking a string as receiver and long as parameter producing a string
GUI.() -> Unit // taking an GUI and producing nothing
이러한 함수 유형에는 수신자 유형 접두사가 붙은 매개 변수 목록이 있습니다.
수신자를 사용하여 코드 해결
실제로 수신기가있는 코드 블록이 처리되는 방식을 이해하는 것은 매우 쉽습니다.
확장 함수와 유사하게 코드 블록이 수신자 유형의 클래스 내에서 평가된다고 상상해보십시오. 이것은 수신자 유형에 의해 효과적으로 수정됩니다.
앞의 예제 인 val intToLong: Int.() -> Long = { toLong() }
에서는 코드 블록이 마치 내부의 함수에 배치 된 것처럼 다른 컨텍스트에서 평가되는 코드 블록이 효과적으로 발생합니다 Int
. 다음은이를 더 잘 보여주는 수제 유형을 사용하는 다른 예입니다.
class Bar
class Foo {
fun transformToBar(): Bar = TODO()
}
val myBlockOfCodeWithReceiverFoo: (Foo).() -> Bar = { transformToBar() }
효과적으로 다음과 같이됩니다 (코드 현명하지 않고 염두에 두십시오-실제로 JVM에서 클래스를 확장 할 수 없습니다).
class Bar
class Foo {
fun transformToBar(): Bar = TODO()
fun myBlockOfCode(): Bar { return transformToBar() }
}
val myBlockOfCodeWithReceiverFoo: (Foo) -> Bar = { it.myBlockOfCode() }
클래스 내부 this
에서 액세스하는 데 사용할 필요가 없는지 확인 transformToBar
하십시오. 수신기가있는 블록에서도 동일한 일이 발생합니다.
단지 등의 설명서 것을 발생 이 또한 코드의 현재 블록이 두 개의 수신기를 가지고있는 경우가 통해 최 수신기를 사용하는 방법에 대해 설명 이 자격 .
잠깐, 여러 수신자?
예. 코드 블록은 여러 수신자를 가질 수 있지만 현재 유형 시스템에는 표현식이 없습니다. 이를 보관하는 유일한 방법 은 단일 수신기 함수 유형을 취하는 여러 고차 함수 를 사용하는 것입니다. 예:
class Foo
class Bar
fun Foo.functionInFoo(): Unit = TODO()
fun Bar.functionInBar(): Unit = TODO()
inline fun higherOrderFunctionTakingFoo(body: (Foo).() -> Unit) = body(Foo())
inline fun higherOrderFunctionTakingBar(body: (Bar).() -> Unit) = body(Bar())
fun example() {
higherOrderFunctionTakingFoo {
higherOrderFunctionTakingBar {
functionInFoo()
functionInBar()
}
}
}
Kotlin 언어의이 기능이 DSL에 적합하지 않은 것 같으면 @DslMarker 가 친구입니다!
결론
Why does all of this matter? With this knowledge:
- you now understand why you can write
toLong()
in an extension function on a number, instead of having to reference the number somehow. Maybe your extension function shouldn't be an extension? - You can build a DSL for your favorite markup language, maybe help parsing the one or other (who needs regular expressions?!).
- You understand why
with
, a standard library function and not a keyword, exists - the act of amending the scope of a block of code to save on redudant typing is so common, the language designers put it right in the standard library. - (maybe) you learned a bit about function types on the offshoot.
Function Literals/Lambda with Receiver
Kotlin supports the concept of “function literals with receivers”. It enables the access on visible methods and properties of a receiver of a lambda in its body without any additional qualifiers. This is very similar to extension functions in which it’s also possible to access visible members of the receiver object inside the extension.
A simple example, also one of the greatest functions in the Kotlin standard library, isapply
:
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
As you can see, such a function literal with receiver is taken as the argument block
here. This block is simply executed and the receiver (which is an instance of T
) is returned. In action this looks as follows:
val foo: Bar = Bar().apply {
color = RED
text = "Foo"
}
We instantiate an object of Bar
and call apply
on it. The instance of Bar
becomes the “receiver”. The block
, passed as an argument in {}
(lambda expression) does not need to use additional qualifiers to access and modify the shown visible properties color
and text
.
The concept of lambdas with receiver is also the most important feature for writing DSLs with Kotlin.
var greet: String.() -> Unit = { println("Hello $this") }
this defines a variable of type String.() -> Unit
, which tells you
String
is the receiver() -> Unit
is the function type
Like F. George mentioned above, all methods of this receiver can be called in the method body.
So, in our example, this
is used to print the String
. The function can be invoked by writing...
greet("Fitzgerald") // result is "Hello Fitzgerald"
the above code snippet was taken from Kotlin Function Literals with Receiver – Quick Introduction by Simon Wirtz.
Simply put ( without any extra words or complications) , the "Receiver" is the type being extended in the extension function or the class name. Using the examples given in answers above
fun Foo.functionInFoo(): Unit = TODO()
Type "Foo" is the "Receiver"
var greet: String.() -> Unit = { println("Hello $this") }
Type "String" is the "Receiver"
Additional tip: Look out for the Class before the fullstop(.) in the "fun" (function) declaration
fun receiver_class.function_name() {
//...
}
ReferenceURL : https://stackoverflow.com/questions/45875491/what-is-a-receiver-in-kotlin
'Development Tip' 카테고리의 다른 글
Webview는 onReceivedSslError 구현시 Google Play의 보안 경고를 방지합니다. (0) | 2020.12.29 |
---|---|
두 개의 클래스가있는 getElementsByClassName () (0) | 2020.12.29 |
Dockerfile에서 WORKDIR의 요점은 무엇입니까? (0) | 2020.12.29 |
다른 div 내에서 두 div를 가로로 배치하는 방법 (0) | 2020.12.29 |
Xcode : 소스 코드를 직접 수정하는 모든 빌드 전에 스크립트 실행 (0) | 2020.12.29 |