Kotlin - 字符串插值 $ vs 使用加号 += 连接
Kotlin - String interpolation $ vs concatenate using plus-equals +=
问题很简单:
这两个版本有什么区别(都初始化了var name: String
和val someInt: Int
)?
name += " $someInt"
name = "$name $someInt"
我也读到 ,所以第二个代码应该优先于第一个代码(使用连接)?
语义是等价的,第二个可能稍微更有效率,但不完全是因为你给出的原因:它只有一个连接而不是两个。 (第一个先生成" " + someInt
,再生成name + (" " + someInt)
。)
找出差异的最佳方法是查看生成的字节码(我将使用 Kotlin 1.4.10)。
为 name += " $someInt"
生成的字节码:
ALOAD 0
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
SWAP
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
BIPUSH 32
INVOKEVIRTUAL java/lang/StringBuilder.append (C)Ljava/lang/StringBuilder;
ILOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 0
为 name = "$name $someInt"
生成的字节码:
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 0
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
BIPUSH 32
INVOKEVIRTUAL java/lang/StringBuilder.append (C)Ljava/lang/StringBuilder;
ILOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 0
结果几乎相同,但在第一种情况下有一个额外的 SWAP
操作,导致第一个 append
操作的参数过早加载到堆栈(在 StringBuilder
已创建,现在需要交换它们)。
TL;DR
结果是:
StringBuilder
在两种情况下都被创建
- 两种情况下都有 3 个追加(
name
、空格和 someInt
)
- 第二种效果稍微好一点。
问题很简单:
这两个版本有什么区别(都初始化了var name: String
和val someInt: Int
)?
name += " $someInt"
name = "$name $someInt"
我也读到
语义是等价的,第二个可能稍微更有效率,但不完全是因为你给出的原因:它只有一个连接而不是两个。 (第一个先生成" " + someInt
,再生成name + (" " + someInt)
。)
找出差异的最佳方法是查看生成的字节码(我将使用 Kotlin 1.4.10)。
为 name += " $someInt"
生成的字节码:
ALOAD 0
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
SWAP
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
BIPUSH 32
INVOKEVIRTUAL java/lang/StringBuilder.append (C)Ljava/lang/StringBuilder;
ILOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 0
为 name = "$name $someInt"
生成的字节码:
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 0
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
BIPUSH 32
INVOKEVIRTUAL java/lang/StringBuilder.append (C)Ljava/lang/StringBuilder;
ILOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 0
结果几乎相同,但在第一种情况下有一个额外的 SWAP
操作,导致第一个 append
操作的参数过早加载到堆栈(在 StringBuilder
已创建,现在需要交换它们)。
TL;DR
结果是:
StringBuilder
在两种情况下都被创建- 两种情况下都有 3 个追加(
name
、空格和someInt
) - 第二种效果稍微好一点。