preface
This blog is my study notes, if there is something wrong, please point out in the comment section, please forgive me
Previous link
If the last argument in the function is a closure, then the last argument can be written after the parentheses instead of inside the parentheses. If there is only one argument, the parentheses can also be removed. (This is an important concept that will be used to understand the source code.)
1. The with and run functions
We hope that the comparison of the two functions can deepen our learning impression
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T. () - >R): R = receiver.block()
Copy the code
The with function takes an object of type T and a function that is treated as an extension function. This method basically tells the T object to execute the body function. Since the second argument is a function, the second function can be placed outside parentheses. We can create a block of code in the second argument that uses this and directly accesses public methods and properties to return the last line of results.
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T. () - >R): R = block()
Copy the code
The run function is also an extension function. Similar to the apply function, except that the run function uses the last line of return, and the apply function returns its current object, this. (We’ll talk about the apply function at the end)
We compare this in both Java and Kotlin
// java
TextView text = findViewById(R.id.tv_text)
text.("ymc")
text.setTextSize(23)
Copy the code
With that in Java code, let’s use kotlin code to write out how the with and run functions work
// kotlin
/ / with function
with(R.id.tv_text) {
tv_text.text = "ymc"
tv_text.textSize = 23f
}
/ / run function
R.id.tv_text.run {
text = "ymc"
textSize = 23f
}
Copy the code
kotlin code
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(2131296283);
int var2 = -1100088;
((TextView)this._$_findCachedViewById(id.tv_text)).setText((CharSequence)"ymc");
((TextView)this._$_findCachedViewById(id.tv_text)).setTextSize(23.0 F);
var2 = -1100088;
((TextView)this._$_findCachedViewById(id.tv_text)).setText((CharSequence)"ymc");
((TextView)this._$_findCachedViewById(id.tv_text)).setTextSize(23.0 F);
}
Copy the code
The above two pieces of code implement the same function, and the kotlin code after conversion is the same, compared to Java, Kotlin code is more concise. The argument in the with/run function is an object, and we can use methods that refer directly to the object’s public properties or methods without using the method name.
Different:
- The with function is an ordinary function, and the run function is an extension function
- Simplicity of the function when it might be empty
- Since the run function is a combination of the let and with functions, it makes up for the fact that the let function must use it arguments instead of objects in the body of the function. In the run function, it can be omitted like the with function, and directly access the public properties and methods of the instance. On the other hand, it makes up for the null judgment problem of the object passed in to the with function. The run function can do the same thing as the let function. It can be used in any scenario of the let,with function.
Let’s take an example where WebSetting may be empty and see how these two functions behave:
/ / with function
with(webview.settings) {
this? .javaScriptEnabled =true
this? .databaseEnabled =true}}/ / run functionwebview.settings? .run { javaScriptEnabled =true
databaseEnabled = true
}
Copy the code
In this case, the run extension function is obviously better because we can check nullability before using it. If you need to use an object multiple times in a piece of code, you can use the with/run function.
2. Let function and run function
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) - >R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)}Copy the code
The let function is an extension function that defaults to the current object as the it argument to the closure and returns the last line in the function, or specifies return
If we compare t. ray and t. let, the two functions are very similar, the only difference is that they take different parameters. The same logic for both functions is shown below.
/ / run functionstring? .run { println("The length of this String is $length")}/ / functionstring? .let { println("The length of this String is ${it.length}")}Copy the code
kotlin code
String string = "ymc";
String var4 = "The length of this String is " + string.length();
System.out.println(var4);
var4 = "The length of this String is " + string.length();
System.out.println(var4);
Copy the code
If you look at the t.run function declaration, you’ll notice that t.run is only treated as a block of calls to the block: t. () extension function. Therefore, in its scope, T can be referred to by this. In most cases this can be omitted during coding. So in our example above, we can use length instead of length instead of length in println statements instead of {this.lenght}. So I’m going to call this passing this argument
The declaration of T et, you’ll notice that T et is passed itself to the function block: (T). So this is similar to passing a lambda expression as a parameter. It can be referred to within the scope of a function using it. So I’m going to call this passing it parameters
3. Let function and Also function
fun <T> T.also(block: (T) - >Unit): T
Copy the code
The also function is an extension function that defaults to the current object as the it parameter of the closure, returning the passed parameter itself.
Let’s compare the differences and similarities between let and also.
/ / functionstring? .let { println("The length of this String is ${it.length}")}/ / braking functionstring? .also { println("The length of this String is ${it.length}")}Copy the code
However, they differ subtly in that their return value let returns a different type of value, while also returns the T type itself, which is this.
Both functions are useful for chaining calls to functions, where let lets you evolve operations and ALSO lets you perform operations on the same variables.
There’s a way we can understand it better
// Normal use
fun makeDir(path: String): File {
val result = File(path)
result.mkdirs()
return result
}
// Combine
fun makeDir(path: String) = path.let{ File(it) }.also{ it.mkdirs() }
Copy the code
From the code above we can see that the let function passes String, but returns a File object (by default, returns the result of the last line of the expression). Also returns File, which is it itself
3. Apply the function
fun <T> T.apply(f: T. () - >Unit): T
Copy the code
The apply function is also an extension function. Within the scope of the function, you can call any method on the object and return the object
Let’s look at an example of how apply works
/ / normal
fun createIntent(intentData: String, intentAction: String): Intent {
val intent = Intent()
intent.action = intentAction
intent.data=Uri.parse(intentData)
return intent
}
/ / the apply function
fun createIntent(intentData: String, intentAction: String) =
Intent().apply { action = intentAction }
.apply { data = Uri.parse(intentData) }
Copy the code
Multiple library functions in the selection of the standard (original source has been confused who is the actual)