执行顺序 - Kotlin
Order of execution - Kotlin
我已经尝试调试下一个程序以了解执行顺序,但我仍然对执行顺序感到困惑
fun foo(): String{
println("Calculating foo...")
return "foo"
}
fun main(args: Array<String>) {
println("First ${foo()}, Second ${foo()}!")
}
// Result:
//
// Calculating foo...
// Calculating foo...
// First foo, Second foo!
// I though the execution would show something like this:
//
// First Calculating foo...foo,
// Second Calculating foo...foo!
main不是要执行的初始函数吗?
如果是,那么 println 将是第一句话,因此(对我而言)执行将从左到右开始(我正确吗?),所以...如果是第一个要显示的词是 First ,然后它将被称为 foo() 函数,这将是 return "foo",这将再次外推到字符串 => ${} ...我说得对吗?
如果不是,我误会了什么?
感谢您的澄清。
这里有两个概念:
- 字符串插值将使用您的函数的输出来构建输出文本。 foo() 中的 println 调用是 side-effect,不包含在 return 值中。因此,它不会被添加到生成的字符串中。
- main函数中的println会收到String插值的结果。文本在传递给 println 之前被完全解释。这就是为什么您按原样看到输出的原因:为了创建最终文本,kt 将首先执行每个字符串表达式,然后构建要显示的整个字符串,最后将准备好的文本传递给 println 函数。
代码执行顺序与自然阅读顺序没有强绑定关系。有运算符优先级的概念,在执行函数时,它的所有参数都必须在传递给它之前进行评估(closures/lambda 除外,但这是一个更复杂的主题)。还有更多的规则。我只能鼓励你参加一般的编程课程来发现所有这些,因为有很多话要说,很难将所有内容都包含在一个 SO 答案中。
Kotlin's String templates 静态解析,并转换为与字符串串联的相应 variable/function 调用。
像"test ${foo()} test2"
这样的文字在JVM字节码中将被编译为"test " + foo() + "test2"
。
基本上,你的函数调用,
println("First ${foo()}, Second ${foo()}!")
被砍成这样:
println("First " + foo() + ", Second " + foo() + "!")
这将执行如下:
println( "First ".plus(foo()).plus(", Second ").plus(foo()).plus("!") )
所以首先,所有的 foo
调用都是在以上述方式连接所有字符串之后进行的,最终字符串作为参数发送给 println()
你可以这样想
- 执行 main() 函数。
- 评估 println() 函数的参数。
"First ${foo()}, Second ${foo()}!"
使用的是字符串插值,所以我们需要先对字符串进行插值。
- 首先通过调用 foo()
进行插值 ${foo()}
- 第一个 foo() 打印
"Calculating foo..."
- 通过调用 foo()
插入第二个 ${foo()}
- 第一个 foo() 打印
"Calculating foo..."
- 现在我们有了内插字符串
First foo, Second foo!
- 执行
println("First foo, Second foo!")
我已经尝试调试下一个程序以了解执行顺序,但我仍然对执行顺序感到困惑
fun foo(): String{
println("Calculating foo...")
return "foo"
}
fun main(args: Array<String>) {
println("First ${foo()}, Second ${foo()}!")
}
// Result:
//
// Calculating foo...
// Calculating foo...
// First foo, Second foo!
// I though the execution would show something like this:
//
// First Calculating foo...foo,
// Second Calculating foo...foo!
main不是要执行的初始函数吗? 如果是,那么 println 将是第一句话,因此(对我而言)执行将从左到右开始(我正确吗?),所以...如果是第一个要显示的词是 First ,然后它将被称为 foo() 函数,这将是 return "foo",这将再次外推到字符串 => ${} ...我说得对吗? 如果不是,我误会了什么?
感谢您的澄清。
这里有两个概念:
- 字符串插值将使用您的函数的输出来构建输出文本。 foo() 中的 println 调用是 side-effect,不包含在 return 值中。因此,它不会被添加到生成的字符串中。
- main函数中的println会收到String插值的结果。文本在传递给 println 之前被完全解释。这就是为什么您按原样看到输出的原因:为了创建最终文本,kt 将首先执行每个字符串表达式,然后构建要显示的整个字符串,最后将准备好的文本传递给 println 函数。
代码执行顺序与自然阅读顺序没有强绑定关系。有运算符优先级的概念,在执行函数时,它的所有参数都必须在传递给它之前进行评估(closures/lambda 除外,但这是一个更复杂的主题)。还有更多的规则。我只能鼓励你参加一般的编程课程来发现所有这些,因为有很多话要说,很难将所有内容都包含在一个 SO 答案中。
Kotlin's String templates 静态解析,并转换为与字符串串联的相应 variable/function 调用。
像"test ${foo()} test2"
这样的文字在JVM字节码中将被编译为"test " + foo() + "test2"
。
基本上,你的函数调用,
println("First ${foo()}, Second ${foo()}!")
被砍成这样:
println("First " + foo() + ", Second " + foo() + "!")
这将执行如下:
println( "First ".plus(foo()).plus(", Second ").plus(foo()).plus("!") )
所以首先,所有的 foo
调用都是在以上述方式连接所有字符串之后进行的,最终字符串作为参数发送给 println()
你可以这样想
- 执行 main() 函数。
- 评估 println() 函数的参数。
"First ${foo()}, Second ${foo()}!"
使用的是字符串插值,所以我们需要先对字符串进行插值。
- 首先通过调用 foo() 进行插值
- 第一个 foo() 打印
"Calculating foo..."
- 通过调用 foo() 插入第二个
- 第一个 foo() 打印
"Calculating foo..."
- 现在我们有了内插字符串
First foo, Second foo!
- 现在我们有了内插字符串
- 执行
println("First foo, Second foo!")
${foo()}
${foo()}