When would we ever need with
in Kotlin if we can already use apply
, run
, also
and let
?
Can anyone give me a clear example?
CodePudding user response:
In most situations, a with
call can be transformed to a run
like this:
with(foo) {
// some code ...
}
// is the same as:
foo.run {
// the same code ...
}
run
and with
will both return the lambda result, and will use foo
as the lambda receiver.
However, I can think of one case where this wouldn't work - when foo
declares its own run
method that takes a lambda, e.g.
// having something like this isn't too uncommon, right?
fun run(x: () -> Unit) {}
The lambda type doesn't have to be exactly the same as the scope function run
. Any function type should work. Then overload resolution wouldn't resolve to the built-in run
.
You can force the resolution by doing some casts, but using with
in this case is much better. Don't you agree?
CodePudding user response:
I don’t think there’s any better example than with(context)
. Maybe it’s not clear if English isn’t one of your primary languages, but it semantically is translated into English much clearer than context.run
when the object is being used to produce a result but isn’t the primary actor, so it makes code a little easier to read.
This of course raises the question of why run
exists. Well, it semantically makes more sense in English when the object is the thing doing the action. In English, the context of an action is what you’re doing something with. But if the object is what is directly producing the result, then it is running the action.
Also, you can’t do ?.with
.
CodePudding user response:
While the basic usage of all of them is same but there are some differences between let
, apply
, run
and with
keywords in kotlin. As you can see in this example:
Now let's see some differences:
- See that here, intent object is nullable. when the receiver object is null -
let
,apply
andrun
don't recognize the property flags whilewith
doesn't have a problem.
- Now another difference is in the result when using these keywords.
For example, apply
keyword:
The apply
function is invoked on a receiver T, and the receiver T also becomes the result of apply
automatically.
//returns receiver T, T exposed as `this`
fun <T> T.apply(block: T.() -> Unit): T
And with
keyword,
The with
function, as opposed to all other scope functions (let
, run
, apply
), is not defined as an extension function. Instead, the function is invoked with a receiver object as its first argument explicitly. The result is the last statement.
//return arbitrary value R, not an extension function, T exposed as
this
fun <T, R> with(receiver: T, block: T.() -> R): R
Example:
val result = with(Intent()) {
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
"RESULE"
}
val result2 = this.apply {
actionBar?.title = "abc"
templateViewModel = TemplateViewModel(repository = ProductRepository(null))
}
result is a string, and result2 is TemplateActivity