Kotlin-1.1-基本类型

来源:互联网 发布:wifi mac地址查询 编辑:程序博客网 时间:2024/05/22 15:52

翻译自官方权威文档。Kotlin官方权威文档-Basics types(英文版)
在原文基础上会补充知识点和例程,如有纰漏和错误,欢迎指点,感谢!

1-基本类型

Kotlin中,万物皆对象意味着我们可以在任何变量上调用成员方法和属性。一些类型有一定特殊的内在表示-例如,数字、字符、布尔数都可以在运行时作为原始值来表示,但是对于用户来说它们看来就像普通的类。在本节里我们会介绍用在Kotlin中的基础类型:数字,字符,布尔值,数组和字符串。

Everything is Object(万物皆对象)是OOP(面向对象编程)的五大基本原则之一

1-数字

Kotlin处理数字的方法和java很像,但是不是完全一样。比如,没有隐式的数字的扩大转换(int转long),并且在一些情况下字面值(literals)有轻微的不同。

Kotlin提供下列内置类型来表示数字(和java很像)

Type Bit width Double 64 Float 32 Long 64 Int 32 Short 16 Byte 8
  • 注意在Kotlin中字符不是数字

1-字面值常量

有下列几种字面值常量用于整数值。

  • 十进制: 123
    • 长整型数Long用L来标识: 123L
  • 十六进制: 0x0F
  • 二进制: 0b00001011

注意!八进制字面值是不支持的。

Kotlin还支持浮点数的传统符号:

  • Double(默认是双精度浮点数): 123.5, 123.5e10
  • Float(需要用fF标记): 123.5f

2-在数值型字面值的下划线

你可以用下划线提升数字常量的可读性。

val oneMillion = 1_000_000val creditCardNumber = 1234_5678_9012_3456Lval socialSecurityNumber = 999_99_9999Lval hexBytes = 0xFF_EC_DE_5Eval bytes = 0b11010010_01101001_10010100_10010010

3-代表

在java平台,数字作为JVM原始类型被物理存储,除非我们需要一个可为空的数字引用(例如Int?)或者泛型。在后者的情况下数字是被打包的。

注意到数字的打包不一定保留身份:

val a: Int = 10000print(a === a) // Prints 'true'val boxedA: Int? = aval anotherBoxedA: Int? = aprint(boxedA === anotherBoxedA) // !!!Prints 'false'!!!

Int?就是可空类型

另一方面,它会保留相等。

val a: Int = 10000print(a == a) // Prints 'true'val boxedA: Int? = aval anotherBoxedA: Int? = aprint(boxedA == anotherBoxedA) // Prints 'true'

4-显式转换

由于不同的表现形式,小的类型不是大类型的子类型。如下列情况就会出现问题。

// 假设的代码, 不能实际编译:val a: Int? = 1 // 打包的Int (java.lang.Integer)val b: Long? = a // 希望能隐式转换为打包的Long(java.lang.Long),但是这里会报错!print(a == b) //会提示不能将==应用于Int?和Long?

因此不仅仅是身份,连等式都会报错。

作为结论,小的类型不能隐式地转换为大的类型。这意味着我们不能在没有显式转换的情况下,将一个Byte类型值赋值给Int变量。

val b: Byte = 1 // 字面值被静态确认val i: Int = b // ERROR!出错!

我们可以使用显式转换来扩大数字

val i: Int = b.toInt() // 显式地将Byte转换为Int

每个数字类型都支持下列转换:

—toByte(): Byte—toShort(): Short—toInt(): Int—toLong(): Long—toFloat(): Float—toDouble(): Double—toChar(): Char

隐式转换的缺失很难被注意到,因为类型是从上下文中中被推测出的。算术运算会被合适的转换所加载,例如:

val l = 1L + 3 // Long + Int => Long

5-运算

Kotlin支持数字算术运算的标准集。这些数字被声明为合适类的成员(但是编译器优化了相应的指令). 参考 Operator overloading.

作为按位运算,没有给他们特殊的字符,除了命名函数,这些函数以中缀形式被调用。例如:

val x = (1 shl 2) and 0x000FF000

这里有按位操作的完整列表(只可以用于Int和Long):

名称 作用 补充 shl(bits) 有符号左移 signed shift left (Java’s <<) shr(bits) 有符号右移 signed shift right (Java’s >>) ushr(bits) 无符号右移 unsigned shift right (Java’s >>>) and(bits) 按位与 bitwise and or(bits) 按位或 bitwise or xor(bits) 按位异或 bitwise xor inv() 按位反 bitwise inversion

浮点数比较

本节讨论的浮点数操作如下:

—等式确认: a == b and a != b—比较运算符: a < b, a > b, a <= b, a >= b—范围实例化和范围检查: a..b, x in a..b, x !in a..b

当操作数a和b被静态地当做Float、double或者它们相应的可为空的副本(该类型被声明或被推测或是一个smart cast的结果),对数字和范围的操作遵守IEEE 754浮点运算标准。

但是,当操作数是静态类型的浮点数(例如,Any, Comparable<...>,一个类型参数),为了支持泛型用例和提供总排序,使用equalscompareTofloatdouble提供支持,这样违反了标准。比如:

  • NaN 被认为等于它自己
  • NaN 被认为比其他任何元素大包括POSITIVE_INFINITY
  • -0.0 被认为小于 0.0

NaN,是Not a Number的缩写,在IEEE浮点数算术标准(IEEE 754)中定义,表示一些特殊数值(无穷与非数值(NaN)),被许多CPU与浮点运算器所采用。

2-字符Characters

字符使用类型Char来表示。它们不可以被直接当作数字。

fun check(c: Char) {    if (c == 1) { // 错误!不兼容的类型!        // ...    }}

字符字面值在单引号中'1'。特殊字符可以使用反斜杠转义。下列转义的序列是被支持的:\t, \b, \n, \r, \', \", \\ , \$. 要对其他任何字符编码,要使用Unicode转义序列的语法'\uFF00'

我们可以显示地将一个Char转换为一个Int数:

fun decimalDigitValue(c: Char): Int {    if (c !in '0'..'9')        throw IllegalArgumentException("Out of range")    return c.toInt() - '0'.toInt() // Explicit conversions to numbers}

就像数字一样,在需要可以为空的引用时,字符能被打包。打包操作时,身份不会被保留。

3-布尔数

类型Boolean代表布尔数, 并且有两个值: truefalse.

在需要可为空引用时,布尔数能被打包(boxed)。

布尔数的内置操作包括:

  • || – 逻辑或
  • && – 逻辑与
  • ! - 逻辑非

4-数组

Kotlin中使用Array类来表示数组,该类有getset方法(能通过操作符重载转换变成[]),还有size属性,和一些其他有用的成员方法。

class Array<T> private constructor() {    val size: Int    operator fun get(index: Int): T    operator fun set(index: Int, value: T): Unit    operator fun iterator(): Iterator<T>    // ...}

为创建数组,我们使用库函数arrayOf(),将数值传入即可。例如arrayOf(1, 2, 3)可以创建数组[1, 2, 3]。作为一种选择,arrayOfNulls()库函数可以用于创建一个给定size的数组,该数组用null元素填满。

另一个选择是用Array构造器,该构造器接受数组size和函数,该函数能够返回给定索引的每个数组元素的初始值:

// 创建元素为String的数组Array<String>,值为["0", "1", "4", "9", "16"]val asc = Array(5, { i -> (i * i).toString() })

正如我们上面说的,[]操作代表调用了成员函数get()set()
As we said above, the [] operation stands for calls to member functions get() and set().

注意:不像java,在Kotlin的数组是不变的。这意味着Kotlin不能让我们将Array<String>赋值到Array<Any>, 这样能放置一个可能的运行时错误(但是你可以使用Array<out Any>,参考Type Projections))。

Kotlin也有特殊的类用于表示原始类型的数组,而不需要过度的打包:ByteArray,ShortArray, IntArray等等。这些类和Array类没有继承关系,但是他们有相同的方法集和属性。他们中的每个都有一致的工厂函数:

val x: IntArray = intArrayOf(1, 2, 3)x[0] = x[1] + x[2]

5-Strings

类型String用于表示字符串。字符串是不可变的。字符串的每个元素都是可以使用s[i]来访问的字符。一个字符串可以使用for循环进行遍历:

for (c in str) {    println(c)}

1-字符串字面值

Kotlin有两种字符串字面值的类型:
1. 转义字符串:可以包含转义字符
2. 原始字符串:包含换行符和任何文本。

转义字符串非常像java字符串:

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(">")

2-字符串模板

字符串可以包含模板表达式——类似于C语言中printf("%d", x)表达式,将x的值替换%d,这种表达式最终会将其结果连接到字符串中。模板表达式通过$标记开头,并由另一个简单名字组成:

val i = 10val s = "i = $i" // 被评估为"i = 10"

或者大括号形式的一个任意表达式:

val s = "abc"val str = "$s.length is ${s.length}" //被评估为"abc.length is 3"

模板被原始字符串和转义字符串支持。如果你想在原始字符串中表示字面值$字符(不支持反斜杠转义),你可以使用下列语法:

val price = """${'$'}9.99"""

本文到此结束!

下面为英文原文。
官网链接:Kotlin官方权威文档-Basics types(英文版)
翻译中如果有纰漏和错误,欢迎指点,感谢!

1-Basic Types

In Kotlin, everything is an object in the sense that we can call member functions and properties on any variable. Some of the types can have a special internal representation - for example, numbers, characters and booleans can be represented as primitive values at runtime - but to the user they look like ordinary classes. In this section we describe the basic types used in Kotlin: numbers, characters, booleans, arrays, and strings.

1-Numbers

Kotlin handles numbers in a way close to Java, but not exactly the same. For example, there are no implicit widening conversions for numbers, and literals are slightly different in some cases.

Kotlin provides the following built-in types representing numbers (this is close to Java):

Type Bit width Double 64 Float 32 Long 64 Int 32 Short 16 Byte 8

Note that characters are not numbers in Kotlin.

Literal Constants

There are the following kinds of literal constants for integral values:

—Decimals: 123  —Longs are tagged by a capital L: 123L—Hexadecimals: 0x0F—Binaries: 0b00001011
  • NOTE: Octal literals are not supported.

Kotlin also supports a conventional notation for floating-point numbers:

—Doubles by default: 123.5, 123.5e10—Floats are tagged by f or F: 123.5f

Underscores in numeric literals (since 1.1)

You can use underscores to make number constants more readable:

val oneMillion = 1_000_000val creditCardNumber = 1234_5678_9012_3456Lval socialSecurityNumber = 999_99_9999Lval hexBytes = 0xFF_EC_DE_5Eval bytes = 0b11010010_01101001_10010100_10010010

Representation

On the Java platform, numbers are physically stored as JVM primitive types, unless we need a nullable number reference (e.g. Int?) or generics are involved. In the latter cases numbers are boxed.

Note that boxing of numbers does not necessarily preserve identity:

val a: Int = 10000print(a === a) // Prints 'true'val boxedA: Int? = aval anotherBoxedA: Int? = aprint(boxedA === anotherBoxedA) // !!!Prints 'false'!!!

On the other hand, it preserves equality:

val a: Int = 10000print(a == a) // Prints 'true'val boxedA: Int? = aval anotherBoxedA: Int? = aprint(boxedA == anotherBoxedA) // Prints 'true'

Explicit Conversions

Due to different representations, smaller types are not subtypes of bigger ones. If they were, we would have troubles of the following sort:

// Hypothetical code, does not actually compile:val a: Int? = 1 // A boxed Int (java.lang.Integer)val b: Long? = a // implicit conversion yields a boxed Long (java.lang.Long)print(a == b) // Surprise! This prints "false" as Long's equals() check for other part to be Long as well

So not only identity, but even equality would have been lost silently all over the place.

As a consequence, smaller types are NOT implicitly converted to bigger types. This means that we cannot assign a value of type Byte to an Int variable without an explicit conversion

val b: Byte = 1 // OK, literals are checked staticallyval i: Int = b // ERROR

We can use explicit conversions to widen numbers

val i: Int = b.toInt() // OK: explicitly widened

Every number type supports the following conversions:

—toByte(): Byte—toShort(): Short—toInt(): Int—toLong(): Long—toFloat(): Float—toDouble(): Double—toChar(): Char

Absence of implicit conversions is rarely noticeable because the type is inferred from the context, and arithmetical operations are overloaded for appropriate conversions, for example

val l = 1L + 3 // Long + Int => Long

Operations

Kotlin supports the standard set of arithmetical operations over numbers, which are declared as members of appropriate classes (but the compiler optimizes the calls down to the corresponding instructions). See Operator overloading.

As of bitwise operations, there’re no special characters for them, but just named functions that can be called in infix form, for example:

val x = (1 shl 2) and 0x000FF000

Here is the complete list of bitwise operations (available for Int and Long only):

—shl(bits) – signed shift left (Java's <<)—shr(bits) – signed shift right (Java's >>)—ushr(bits) – unsigned shift right (Java's >>>)—and(bits) – bitwise andor(bits) – bitwise orxor(bits) – bitwise xor—inv() – bitwise inversion

Floating Point Numbers Comparison

The operations on floating point numbers discussed in this section are:

—Equality checks: a == b and a != b—Comparison operators: a < b, a > b, a <= b, a >= b—Range instantiation and range checks: a..b, x in a..b, x !in a..b

When the operands a and b are statically known to be Float or Double or their nullable counterparts (the type is declared or inferred or is a result of a smart cast), the operations on the numbers and the range that they form follow the IEEE 754 Standard for Floating-Point Arithmetic.

However, to support generic use cases and provide total ordering, when the operands are not statically typed as floating point numbers (e.g. Any, Comparable<...>, a type parameter), the operations use the equals and compareTo implementations for Float and Double, which disagree with the standard, so that:

—NaN is considered equal to itself—NaN is considered greater than any other element including POSITIVE_INFINITY—-0.0 is considered less than 0.0

Characters

Characters are represented by the type Char. They can not be treated directly as numbers

fun check(c: Char) {    if (c == 1) { // ERROR: incompatible types        // ...    }}

Character literals go in single quotes: '1'. Special characters can be escaped using a backslash. The following escape sequences are supported: \t, \b, \n, \r, \', \", \\ and \$. To encode any other character, use the Unicode escape sequence syntax: '\uFF00'.

We can explicitly convert a character to an Int number:

fun decimalDigitValue(c: Char): Int {    if (c !in '0'..'9')        throw IllegalArgumentException("Out of range")    return c.toInt() - '0'.toInt() // Explicit conversions to numbers}

Like numbers, characters are boxed when a nullable reference is needed. Identity is not preserved by the boxing operation.

Booleans

The type Boolean represents booleans, and has two values: true and false.

Booleans are boxed if a nullable reference is needed.

Built-in operations on booleans include

—|| – lazy disjunction—&& – lazy conjunction—! - negation

Arrays

Arrays in Kotlin are represented by the Array class, that has get and set functions (that turn into [] by operator overloading conventions), and size property, along with a few other useful member functions:

class Array<T> private constructor() {    val size: Int    operator fun get(index: Int): T    operator fun set(index: Int, value: T): Unit    operator fun iterator(): Iterator<T>    // ...}

To create an array, we can use a library function arrayOf() and pass the item values to it, so that arrayOf(1, 2, 3) creates an array [1, 2, 3]. Alternatively, the arrayOfNulls() library function can be used to create an array of a given size filled with null elements.

Another option is to use the Array constructor that takes the array size and the function that can return the initial value of each array element given its index:

// Creates an Array<String> with values ["0", "1", "4", "9", "16"]val asc = Array(5, { i -> (i * i).toString() })

As we said above, the [] operation stands for calls to member functions get() and set().

Note: unlike Java, arrays in Kotlin are invariant. This means that Kotlin does not let us assign an Array<String> to an Array<Any>, which prevents a possible runtime failure (but you can use Array<out Any>, see Type Projections).

Kotlin also has specialized classes to represent arrays of primitive types without boxing overhead: ByteArray, ShortArray, IntArray and so on. These classes have no inheritance relation to the Array class, but they have the same set of methods and properties. Each of them also has a corresponding factory function:

val x: IntArray = intArrayOf(1, 2, 3)x[0] = x[1] + x[2]

Strings

Strings are represented by the type String. Strings are immutable. Elements of a string are characters that can be accessed by the indexing operation: s[i]. A string can be iterated over with a for-loop:

for (c in str) {    println(c)}
String Literals

Kotlin has two types of string literals: escaped strings that may have escaped characters in them and raw strings that can contain newlines and arbitrary text. An escaped string is very much like a Java string:

val s = "Hello, world!\n"

Escaping is done in the conventional way, with a backslash. See Characters above for the list of supported escape sequences.

A raw string is delimited by a triple quote ("""), contains no escaping and can contain newlines and any other characters:

val text = """    for (c in "foo")        print(c)"""

You can remove leading whitespace with trimMargin() function:

val text = """    |Tell me and I forget.    |Teach me and I remember.    |Involve me and I learn.    |(Benjamin Franklin)    """.trimMargin()

By default| is used as margin prefix, but you can choose another character and pass it as a parameter, like trimMargin(">").

String Templates

Strings may contain template expressions, i.e. pieces of code that are evaluated and whose results are concatenated into the string. A template expression starts with a dollar sign ($) and consists of either a simple name:

val i = 10val s = "i = $i" // evaluates to "i = 10"

or an arbitrary expression in curly braces:

val s = "abc"val str = "$s.length is ${s.length}" // evaluates to "abc.length is 3"

Templates are supported both inside raw strings and inside escaped strings. If you need to represent a literal $character in a raw string (which doesn’t support backslash escaping), you can use the following syntax:

val price = """${'$'}9.99"""
原创粉丝点击