Kotlin 2.1.0 入门教程(五)
无符号整型
无符号整型包括以下几种:
-
UByte
,8 位无符号整数,范围是0
到255
。 -
UShort
,16 位无符号整数,范围是0
到65535
。 -
UInt
,32 位无符号整数,范围是0
到2^32 - 1
(4294967295
)。 -
ULong
,64 位无符号整数,范围是0
到2^64 - 1
(18446744073709551615
)。
val uByte: UByte = 255u
val uShort: UShort = 65535u
val uInt: UInt = 4294967295u
val uLong: ULong = 18446744073709551615u
注意,无符号字面量需要在数字后面加上 u
或 U
后缀。
u
和 U
标记用于无符号字面量。具体类型根据预期类型确定。如果未提供预期类型,编译器将根据字面量的大小使用 UInt
或 ULong
。
val b: UByte = 1u // UByte,提供了预期类型。
val s: UShort = 1u // UShort,提供了预期类型。
val i: UInt = 1u // UInt,提供了预期类型。
val l: ULong = 1u // ULong,提供了预期类型。
val a1 = 42u // UInt,未提供预期类型,常量适合 UInt。
val a2 = 0xFFFF_FFFF_FFFFu // ULong,未提供预期类型,常量不适合 UInt。
uL
和 UL
显式将字面量标记为无符号长整型 ULong
。
val a = 1UL
无符号整型数组
无符号整型数组的类型有:
-
UByteArray
-
UShortArray
-
UIntArray
-
ULongArray
与有符号整型数组类似,它们提供了与 Array
类相似的 API,但没有装箱开销。
无符号整型数组及其操作处于 Beta 阶段。它们可能会随时以不兼容的方式更改。
当使用无符号整型数组时,会收到一条警告,表明此功能尚未稳定。要消除警告,请使用 @ExperimentalUnsignedTypes
注解选择加入。
UInt
和 ULong
的范围和级数由 UIntRange
、UIntProgression
、ULongRange
和 ULongProgression
类支持。这些类与无符号整型一起是稳定的。
布尔类型
Boolean
类型表示布尔对象,可以有两个值:true
和 false
。
Boolean
有一个可空对应类型 Boolean?
。
在 JVM 上,存储为原始 boolean
类型的布尔值通常使用 8 位。
在 JVM 上,对布尔对象的可空引用会被装箱为 Java 类,就像数字类型一样。
字符类型
字符由 Char
类型表示。字符字面量用单引号括起来 '1'
。
在 JVM 上,存储为原始类型 char
的字符表示 16 位 Unicode 字符。
特殊字符以转义反斜杠 \
开头。支持以下转义序列:
-
\t
—— 制表符 -
\b
—— 退格符 -
\n
—— 换行符(LF) -
\r
—— 回车符(CR) -
\'
—— 单引号 -
\"
—— 双引号 -
\\
—— 反斜杠 -
\$
—— 美元符号
要编码任何其他字符,请使用 Unicode 转义序列语法:'\uFF00'
。
如果字符变量的值是数字,可以使用 digitToInt()
函数将其显式转换为 Int
数字。
在 JVM 上,当需要可空引用时,字符会被装箱为 Java 类,就像数字类型一样。装箱操作不会保留同一性。
字符串
字符串由 String
类型表示。
在 JVM 上,String
类型的对象使用 UTF-16 编码,每个字符大约占用 2 个字节。
字符串值是用双引号 "
括起来的字符序列。
val str = "abcd 123"
字符串的元素是字符,可以通过索引操作 s[i]
访问。可以使用 for
循环遍历这些字符。
for (c in str) {
println(c)
}
字符串是不可变的。一旦初始化字符串,就无法更改其值或为其分配新值。所有转换字符串的操作都会返回一个新的 String
对象,而原始字符串保持不变。
val str = "abcd"
// 创建并打印一个新的 String 对象。
println(str.uppercase()) // ABCD
// 原始字符串保持不变。
println(str) // abcd
要连接字符串,请使用 +
操作符。这也适用于将字符串与其他类型的值连接,只要表达式中的第一个元素是字符串。
val s = "abc" + 1
println(s + "def") // abc1def
在大多数情况下,使用字符串模板或多行字符串比字符串连接更可取。
字符串字面量
有两种类型的字符串字面量:
-
转义字符串
-
多行字符串
转义字符串可以包含转义字符。以下是一个转义字符串的示例:
val s = "Hello, world!\n"
多行字符串可以包含换行符和任意文本。它由三重引号 """
分隔,不包含转义,并且可以包含换行符和任何其他字符:
val text = """
for (c in "foo")
print(c)
"""
要从多行字符串中删除前导空白,请使用 trimMargin()
函数:
val text = """
|Tell me and I forget.
|Teach me and I remember.
|Involve me and I learn.
|(Benjamin Franklin)
""".trimMargin()
默认情况下,管道符号 |
用作边距前缀,但您可以选择另一个字符并将其作为参数传递,例如 trimMargin(">")
。
字符串模板
字符串字面量可以包含模板表达式,这些代码片段会被求值,并将其结果连接到字符串中。
当处理模板表达式时,Kotlin 会自动调用表达式结果的 .toString()
函数,将其转换为字符串。模板表达式以美元符号 $
开头,可以是变量名:
val i = 10
println("i = $i") // i = 10
val letters = listOf("a","b","c","d","e")
println("Letters: $letters") // Letters: [a, b, c, d, e]
或者用花括号括起来的表达式:
val s = "abc"
println("$s.length is ${s.length}") // abc.length is 3
可以在多行字符串和转义字符串中使用模板。然而,多行字符串不支持反斜杠转义。要在多行字符串中插入美元符号 $
,请在标识符开头的任何符号前使用以下语法:
fun main() {
val p = 1
val str = """
$p ${p + 1} ${'$'}_9.99
"""
val str2 = "$p ${p + 1} \$_9.99"
println(str) // 1 2 $_9.99
println(str2) // 1 2 $_9.99
}
为了避免在字符串中使用 ${'$'}
序列,可以使用实验性的多美元字符串插值功能。
多美元字符串插值
多美元字符串插值是实验性的,需要明确选择加入。
多美元字符串插值允许您指定需要多少个连续的美元符号来触发插值。插值是将变量或表达式直接嵌入字符串的过程。
虽然可以为单行字符串转义字面量,但多行字符串不支持反斜杠转义。要在多行字符串中包含美元符号 $
作为字面字符,必须使用 ${'$'}
结构来防止字符串插值。这种方法可能会使代码更难阅读,尤其是在字符串包含多个美元符号时。
多美元字符串插值通过允许您在单行和多行字符串中将美元符号视为字面字符来简化这一点。
val KClass<*>.jsonSchema : String
get() = $$"""
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"$dynamicAnchor": "meta"
"title": "$${simpleName ?: qualifiedName ?: "unknown"}",
"type": "object"
}
"""
在这里,$$
前缀指定需要两个连续的美元符号来触发字符串插值。单个美元符号保持为字面字符。
您可以调整触发插值所需的美元符号数量。例如,使用三个连续的美元符号 $$$
允许 $
和 $$
保持为字面字符,同时启用 $$$
的插值:
val productName = "carrot"
val requestedData = $$$"""{
"currency": "$",
"enteredAmount": "42.45 $$",
"$$serviceField": "none",
"product": "$$$productName"
}
"""
//{
// "currency": "$",
// "enteredAmount": "42.45 $$",
// "$$serviceField": "none",
// "product": "carrot"
//}
println(requestedData)
在这里,$$$
前缀允许字符串包含 $
和 $$
,而无需使用 ${'$'}
结构进行转义。
要启用此功能,请在命令行中使用以下编译器选项:
kotlinc -Xmulti-dollar-interpolation main.kt
或者,更新 Gradle 构建文件的 compilerOptions {}
块:
// build.gradle.kts
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xmulti-dollar-interpolation")
}
}
此功能不会影响使用单美元字符串插值的现有代码。您可以继续像以前一样使用单个 $
,并在需要处理字符串中的字面美元符号时应用多美元符号。
字符串格式化
使用 String.format()
函数的字符串格式化仅在 Kotlin/JVM 中可用。
要根据特定需求格式化字符串,请使用 String.format()
函数。
String.format()
函数接受一个格式字符串和一个或多个参数。格式字符串包含一个占位符(由 %
表示)用于给定的参数,后跟格式说明符。格式说明符是用于相应参数的格式化指令,由标志、宽度、精度和转换类型组成。格式说明符共同决定了输出的格式。常见的格式说明符包括用于整数的 %d
、用于浮点数的 %f
和用于字符串的 %s
。您还可以使用 argument_index$
语法在格式字符串中以不同格式多次引用同一个参数。
有关详细理解和格式说明符的完整列表,请参阅 java.util.Formatter
文档。
// 格式化整数,添加前导零以达到七个字符的长度。
val integerNumber = String.format("%07d", 31416)
println(integerNumber) // 0031416
// 格式化浮点数以显示带有 + 号和四位小数。
val floatNumber = String.format("%+.4f", 3.141592)
println(floatNumber) // +3.1416
// 格式化两个字符串为大写,每个占位符对应一个字符串
val helloString = String.format("%S %S", "hello", "world")
println(helloString) // HELLO WORLD
// 将负数格式化为用括号括起来,然后以不同格式(不带括号)重复相同的数字,使用 argument_index$。
val negativeNumberInParentheses = String.format("%(d means %1\$d", -31416)
println(negativeNumberInParentheses) //(31416) means -31416
String.format()
函数提供了与字符串模板类似的功能。然而,String.format()
函数更加灵活,因为有更多的格式化选项可用。
此外,您可以从变量中分配格式字符串。这在格式字符串发生变化时非常有用,例如,在依赖于用户区域设置的本地化情况下。
使用 String.format()
函数时要小心,因为很容易将参数的数量或位置与其对应的占位符不匹配。