-
Notifications
You must be signed in to change notification settings - Fork 4.5k
[upd] this expressions #5657
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
[upd] this expressions #5657
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,42 +1,218 @@ | ||
| [//]: # (title: This expressions) | ||
|
|
||
| To denote the current _receiver_, you use `this` expressions: | ||
| The `this` expression refers to the current object or receiver. | ||
|
|
||
| How you use `this` depends on the context: | ||
|
|
||
| * In a member of a [class](classes.md#inheritance), `this` refers to the current object of that class. | ||
| * In an [extension function](extensions.md) or a [function literal with receiver](lambdas.md#function-literals-with-receiver) | ||
| `this` denotes the _receiver_ parameter that is passed on the left-hand side of a dot. | ||
|
|
||
| If `this` has no qualifiers, it refers to the _innermost enclosing scope_. To refer to `this` in other scopes, _label qualifiers_ are used: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is actually very important: class Foo {
fun foo() { }
}
class Bar {
fun bar() { }
fun Foo.moo() {
this.bar() // 'this' refers to the enclosing 'Bar' instance
this.foo() // 'this' refers to the extension receiver
}
}
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added to the Qualified this section. Do you think it also makes sense to include the example like the one you've provided?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still think this is incorrect. You write "If
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it now, thank you! What do you think about smth like this: Kotlin code can have several receivers available at the same time. This happens when receiver scopes are nested. For example, an extension function declared inside a class can access members of both the extension receiver and the enclosing class object.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem with your comment is in the "Unqualified this refers to the receiver with the highest priority in the current scope." part, unqualified
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah in that case my wording is too restrictive ig, so is the following would be correct: Your code can have several receivers available at the same time when receiver scopes are nested. Kotlin can use any available receiver to access its members implicitly, but receivers from inner scopes have higher priority. To explicitly refer to a particular receiver, use a qualified this. This is especially useful when multiple receivers have members with the same name and you need to access a member of an outer receiver. |
||
| For example, in the following code, `this.name` means the `name` property of the current `Language` object: | ||
|
|
||
| ```kotlin | ||
| //sampleStart | ||
| class Language(val name: String) { | ||
| fun printName() { | ||
| println(this.name) | ||
| } | ||
| } | ||
|
|
||
| fun main() { | ||
| val language = Language("Kotlin") | ||
| language.printName() | ||
| // Kotlin | ||
| } | ||
| //sampleEnd | ||
| ``` | ||
| {kotlin-runnable="true"} | ||
|
|
||
| * In an [extension function](extensions.md) or a [function literal with receiver](lambdas.md#function-literals-with-receiver), | ||
| `this` refers to the receiver. | ||
|
|
||
| A _receiver_ is the object that the function works with. In the following example, we call `lastCharacter()`on the string | ||
| `"Kotlin"`. Therefore, `"Kotlin"` is the receiver. Inside the extension function, `this` refers | ||
| to `"Kotlin"`. This means that `this.length` is the length of `"Kotlin"`: | ||
|
|
||
| ```kotlin | ||
| //sampleStart | ||
| fun String.lastCharacter(): Char { | ||
| println(this.length) | ||
| // 6 | ||
| return this[this.length - 1] | ||
| } | ||
|
|
||
| fun main() { | ||
| println("Kotlin".lastCharacter()) | ||
| // n | ||
| } | ||
| //sampleEnd | ||
| ``` | ||
| {kotlin-runnable="true"} | ||
|
|
||
| > In simple cases, you don't need to write `this` explicitly. Kotlin infers it from the current scope. | ||
|
aepanchi marked this conversation as resolved.
Outdated
|
||
| > Learn more about [](#implicit-this). | ||
| > | ||
| {style="tip"} | ||
|
|
||
| ## Qualified this | ||
| ## Qualified this | ||
|
|
||
| To access `this` from an outer scope (a [class](classes.md), [extension function](extensions.md), | ||
| or labeled [function literal with receiver](lambdas.md#function-literals-with-receiver)) you write `this@label`, | ||
| where `@label` is a [label](returns.md) on the scope `this` is meant to be from: | ||
| Your code can have several possible `this` values at the same time. This happens when receiver scopes are nested. For | ||
| example, an inner class can access both its own object and the outer class object. In such cases, plain `this` refers | ||
| to the receiver of the _innermost enclosing scope_. To refer to a receiver from an outer scope, use a qualified `this`. | ||
|
|
||
| To use a qualified `this`, add a [label](returns.md) qualifier: | ||
|
|
||
| ```kotlin | ||
| class A { // implicit label @A | ||
| inner class B { // implicit label @B | ||
| fun Int.foo() { // implicit label @foo | ||
| val a = this@A // A's this | ||
| val b = this@B // B's this | ||
| this@label | ||
| ``` | ||
|
|
||
| val c = this // foo()'s receiver, an Int | ||
| val c1 = this@foo // foo()'s receiver, an Int | ||
| The label tells the compiler which receiver to access. You can use the name of an enclosing class or extension function. | ||
| For example, `this@foo` refers to the receiver of an enclosing extension function named `foo`. | ||
|
|
||
| val funLit = lambda@ fun String.() { | ||
| val d = this // funLit's receiver, a String | ||
| } | ||
| ### Access an outer class from an inner class | ||
|
|
||
| val funLit2 = { s: String -> | ||
| // foo()'s receiver, since enclosing lambda expression | ||
| // doesn't have any receiver | ||
| val d1 = this | ||
| } | ||
| In an [inner class](nested-classes.md#inner-classes), plain `this` refers to the inner class instance. To access the outer class object, | ||
| use qualified `this`: | ||
|
|
||
| ```kotlin | ||
| //sampleStart | ||
| class User(val name: String) { | ||
| inner class Age(val value: Int) { | ||
| fun printInfo() { | ||
|
|
||
| // Refers to the value property of the current Age object | ||
| println(this.value) | ||
| // 22 | ||
|
|
||
| // Refers to the name property of the outer User object | ||
| println(this@User.name) | ||
| // Jane Doe | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fun main() { | ||
| val user = User("Jane Doe") | ||
| val age = user.Age(22) | ||
| age.printInfo() | ||
| } | ||
| //sampleEnd | ||
| ``` | ||
| {kotlin-runnable="true"} | ||
|
|
||
| > Only inner classes hold a reference to an outer class instance. Regular [nested classes](nested-classes.md) don't have access to | ||
| > `this` from the outer class. | ||
| > | ||
| {style="note"} | ||
|
|
||
| ### Access a class from an extension function | ||
|
|
||
| If you declare an extension function inside a class, two receivers are available: | ||
|
|
||
| * The extension receiver: the value on which you call the extension function. | ||
| * The dispatch receiver: the current object of the class where you declare the extension function. | ||
|
|
||
| Use qualified `this` to specify which receiver you need: | ||
|
|
||
| ```kotlin | ||
| //sampleStart | ||
| class User { | ||
| val prefix = "Name" | ||
|
|
||
| fun String.formatName(): String { | ||
| return "${this@User.prefix}: ${this.uppercase()}" | ||
| } | ||
|
|
||
| fun printUser() { | ||
| println("Jane Doe".formatName()) | ||
| } | ||
| } | ||
|
|
||
| fun main() { | ||
| val user = User() | ||
| user.printUser() | ||
| // Name: JANE DOE | ||
| } | ||
| //sampleEnd | ||
| ``` | ||
| {kotlin-runnable="true"} | ||
|
|
||
| Here: | ||
|
|
||
| * `this` refers to the extension receiver (the `"Jane Doe"` string). | ||
| * `this@User` refers to the current `User` object. | ||
| * `this@User.prefix` accesses the prefix property of the current `User` object. | ||
|
|
||
| ### Access from a lambda | ||
|
|
||
| Unlike a regular lambda, a [lambda with receiver](lambdas.md#function-literals-with-receiver) has its own receiver. Therefore, `this` inside it | ||
| refers to that receiver. If a lambda with receiver is nested inside another receiver scope, add a label to the lambda | ||
| and use qualified `this` to specify which receiver you need: | ||
|
|
||
| ```kotlin | ||
| //sampleStart | ||
| class User(val name: String) { | ||
| fun printWithPrefix() { | ||
| val print: String.() -> Unit = stringLabel@ { | ||
| println("${this@stringLabel}: ${this@User.name}") | ||
| } | ||
|
|
||
| print("User") | ||
| } | ||
| } | ||
|
|
||
| fun main() { | ||
| val user = User("Jane Doe") | ||
| user.printWithPrefix() | ||
| // User: Jane Doe | ||
| } | ||
| //sampleEnd | ||
| ``` | ||
| {kotlin-runnable="true"} | ||
|
|
||
| Here: | ||
|
|
||
| * `stringLabel@` labels the lambda. | ||
| * `this@stringLabel` refers to the string receiver of the lambda. | ||
| * `this@User` refers to the current `User` object. | ||
|
|
||
| The label doesn't call anything or change how the lambda works. It only helps you refer to the lambda's receiver. | ||
|
|
||
| ### Access an anonymous object | ||
|
|
||
| Since anonymous objects don’t have class names, you can't use a name like `this@YourClassName` to refer | ||
| to it. Inside an anonymous object, use plain `this` to refer to the object: | ||
|
|
||
| ```kotlin | ||
| //sampleStart | ||
| interface UserPrinter { | ||
| fun print() | ||
| } | ||
|
|
||
| fun printUser(printer: UserPrinter) { | ||
| printer.print() | ||
| } | ||
|
|
||
| fun main() { | ||
| val printer = object : UserPrinter { | ||
| val name = "Jane Doe" | ||
|
|
||
| override fun print() { | ||
| // Refers to the name property of the anonymous object | ||
| println(this.name) | ||
| } | ||
| } | ||
| printUser(printer) | ||
| // Jane Doe | ||
| } | ||
| //sampleEnd | ||
| ``` | ||
| {kotlin-runnable="true"} | ||
|
|
||
| > If you create an anonymous object inside another class, you can use qualified `this` to access the outer class object. | ||
| > Use it to access an outer receiver, not the anonymous object itself. | ||
| > | ||
| {style="tip"} | ||
|
|
||
|
|
||
| ## Implicit this | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.