问题
I'm trying to understand why let is needed. In the example below I have a class Test with a function giveMeFive:
public class Test() {
fun giveMeFive(): Int {
return 5
}
}
Given the following code:
var test: Test? = Test()
var x: Int? = test?.giveMeFive()
test = null
x = test?.giveMeFive()
x = test?.let {it.giveMeFive()}
x gets set to 5, then after test is set to null, calling either of the following statements return null for x. Given that calling a method on a null reference skips the call and sets x to null, why would I ever need to use let? Are some cases where just ?. won't work and let is required?
Further, if the function being called doesn't return anything, then ?. will skip the call and I don't need ?.let there either.
回答1:
let()
fun <T, R> T.let(f: (T) -> R): R = f(this)
let() is a scoping function: use it whenever you want to define a variable for a specific scope of your code but not beyond. It’s extremely useful to keep your code nicely self-contained so that you don’t have variables “leaking out”: being accessible past the point where they should be.
DbConnection.getConnection().let { connection ->
}
// connection is no longer visible here
let() can also be used as an alternative to testing against null:
val map : Map<String, Config> = ...
val config = map[key]
// config is a "Config?"
config?.let {
// This whole block will not be executed if "config" is null.
// Additionally, "it" has now been cast to a "Config" (no
question mark)
}
回答2:
You need to use let
if you want to chain function calls that aren't defined on the type you are chaining from.
Let's say the definition of your function was this instead:
// Not defined inside the Test class
fun giveMeFive(t: Test) {
return 5
}
Now, if you have a nullable Test
and want to call this function in a chain, you have to use let
:
val x = test?.let { giveMeFive(it) }
回答3:
The .let{} extension function in Kotlin:
Takes the object reference as the parameter on which
.let{}
is called.Returns value of any non-primitive data-type which has been returned from with
let{}
function. By default, it returnsundefined
value ofkotlin.Any
class.
Declaration in package kotlin:
public inline fun <T, R> T.let(block: (T) -> R): R {
return block(this)
}
Simple practical demonstration to see how .let{}
extension function works in Kotlin.
Sample Code 1:-
val builder = StringBuilder("Hello ")
println("Print 0: $builder")
val returnVal = builder.let { arg ->
arg.append("World")
println("Print 1: $arg")
"Done" // Returnning some string
}
println("Print 2: $builder")
println("Print 3: $returnVal")
Sample Code 1 Output:-
Print 0: Hello
Print 1: Hello World
Print 2: Hello World
Print 3: Done
In Sample Code 1:
We created the final object of type StringBuilder with initialization value "Hello ".
In
builder.let{}
, the builder object reference will be passed toarg
.Here, the output
Print 2: Hello World
andPrint 3: Hello World
means that thebuilder
andarg
, both are pointing to the sameStringBuilder
object-reference
. That's why they both print the sameString
value.In the last line of
.let{}
function block, we are returning"Done"
String
value which will be assigned toreturnVal
.*Hence, we get
Print 3: Done
output fromreturnVal
.
Sample Code 2:-
val builder = StringBuilder("Hello ")
println("Print 0: $builder")
val returnVal = builder.let { arg ->
arg.append("World")
println("Print 1: $arg")
arg.length
}
println("Print 2: $builder")
println("Print 3: $returnVal") // Now return val is int = length of string.
Sample Code 2 Output:-
Print 0: Hello
Print 1: Hello World
Print 2: Hello World
Print 3: 11
In Sample Code 2:
What's difference:
In the last line of
.let{}
function block, we are returning theInt
value equals to the length of StringBuilder objectarg
whose value at this line of code is"Hello World"
. So length =11
of typeInt
will be assigned toreturnVal
.*Hence, we get
Print 3: 11
as output fromreturnVal
.
Also try these:-
- .run() {}
- .apply() {}
- with(obj) {}
- .also() {}
Happy Coding...
来源:https://stackoverflow.com/questions/54382675/understanding-the-need-for-kotlin-let