receiver-jvm
Of course. Let's dive into Receiver-JVM.
At its core, the concept of a "receiver" in the JVM (Java Virtual Machine) world, particularly in the Kotlin programming language, is a powerful and fundamental feature that enables writing clean, domain-specific APIs. It's not a separate library or tool called "receiver-jvm" but a key language feature on the JVM.
1. What is a Receiver?
A receiver is the object on which a method or an extension function is called. Inside that function, you can access the members of that object without any qualifiers. The receiver is what the keyword this
refers to.
In simpler terms: It's the object you are "in".
Example:
class Printer {
fun printMessage(message: String) {
println(this.javaClass.simpleName) // 'this' is the receiver (a Printer object)
println(message)
}
}
fun main() {
val myPrinter = Printer()
myPrinter.printMessage("Hello") // `myPrinter` is the receiver for the printMessage call
}
Here, inside printMessage
, this
refers to the instance myPrinter
.
2. The Powerhouse: Extension Functions (The Most Common "Receiver-JVM" Usage)
Kotlin's extension functions are the most prominent use case for receivers on the JVM. They allow you to "extend" a class with new functionality without having to inherit from it.
Syntax:
fun ReceiverType.extensionFunction(parameters): ReturnType {
// Inside here, `this` refers to the receiver object
}
Example:
// Adds a new function to the String class (the receiver)
fun String.addEnthusiasm(amount: Int = 1): String {
// `this` is the String we are operating on
return this + "!".repeat(amount)
}
fun main() {
val greeting = "Hello"
println(greeting.addEnthusiasm(3)) // Output: Hello!!!
// The String "Hello" is the receiver for the `addEnthusiasm` call.
}
This is incredibly useful for creating utility functions that feel like native methods of a class (e.g., functions on String
, List
, File
). Many popular Kotlin libraries (like Ktor, Kotlinx DateTime) use this to build fluent and readable DSLs.
3. Advanced Usage: Function Types with Receiver
This is where the concept becomes truly powerful for building Domain-Specific Languages (DSLs). Kotlin allows you to define function types where the function is called in the context of a specific receiver.
Syntax:
lambda: ReceiverType.() -> Unit
This means: "A lambda that must be called on an object of ReceiverType
. Inside that lambda, this
is that object."
Example: Building an HTML DSL
This is a classic example, similar to what the kotlinx.html
library does.
class HTML {
fun body() { println("<body>") }
fun div() { println("<div>") }
}
// The parameter 'init' is a function that is called on an HTML receiver
fun html(init: HTML.() -> Unit): HTML {
val html = HTML() // create a receiver object
html.init() // call the lambda on that receiver, passing the context
return html
}
fun main() {
// Create HTML using a clean, nested DSL-like structure
val myPage = html {
body() // called on the HTML receiver
div() // called on the HTML receiver
}
// Output:
// <body>
// <div>
}
The magic here is that inside the html { ... }
block, you are effectively inside the HTML
class. You can call its methods (body
, div
) directly.
4. How This Relates to the JVM
It's crucial to understand that receivers are a compile-time feature, not a JVM runtime feature. The JVM itself has no inherent concept of a "receiver" in the Kotlin sense.
When Kotlin code with receivers is compiled to JVM bytecode:
-
Extension Functions: Are compiled down to static methods.
- The function
fun String.addEnthusiasm()
becomes a static method likepublic static String addEnthusiasm(String $this, int amount)
. - The receiver becomes the first parameter of the static method.
- The function
-
Function Types with Receiver: Also become standard functional interfaces (like
Function1
). The receiver object is passed as the first argument to the generatedinvoke
method.
The elegance and readability are provided by the Kotlin compiler's syntactic sugar. The JVM simply executes the resulting, standard bytecode.
5. Key Benefits on the JVM Platform
- Readability and Fluency: Enables the creation of APIs that read like natural language or specialized DSLs (e.g., for HTML, SQL, HTTP routing).
- Scoping and Safety: Functions with receivers can only be called in a context where the receiver is available, which can prevent API misuse.
- Code Organization: Allows you to organize functions logically (as extensions on the types they relate to) rather than in static utility classes, reducing the need for "helper" or "util" classes.
- Interoperability: Since it compiles to standard JVM bytecode, Java code can call Kotlin extension functions (though the syntax is less elegant:
MyUtilsKt.addEnthusiasm("Hello", 3)
).
Summary
Concept | Description | JVM Compilation |
---|---|---|
Receiver | The object a function is called on (this ). |
N/A (A general OOP concept) |
Extension Function | A function that extends a class, with that class as its receiver. | Static method with the receiver as the first parameter. |
Function Type with Receiver | A lambda that must be called in the context of a specific object. | A standard functional interface where the invoke method takes the receiver as its first parameter. |
So, when you hear "receiver-jvm," it's most likely referring to leveraging these powerful Kotlin language features on the JVM platform to write more expressive, concise, and maintainable code.
本文来自博客园,作者:ukyo--碳水化合物,转载请注明原文链接:https://www.cnblogs.com/ukzq/p/19069677