zoukankan      html  css  js  c++  java
  • KOTLIN开发语言文档(官方文档) -- 2.基本概念

    网页链接:https://kotlinlang.org/docs/reference/basic-types.html

    2.   基本概念

    2.1.  基本类型

    从可以在任何变量处理调用成员函数和属性角度来说,在Kotlin开发语言中,一切都是对象。有些类型是内嵌的,它们的实现进行过优化,用户看到的仍是原始类。在这节中,我们说明大部分这些类型:数字,字符,布尔和数组。

    2.1.1.   数字

    Kotlin开发语言处理数组的方法类似Java开发语言,但是也有差别。例如,没有隐含的数字扩宽的转换,并且在相同的情况下,文字也有些不同。

    Kotlin开发语言提供下列内嵌类型表示数字(这是类似Java开发语言):

    类型

    位宽度

    Double

    64

    Float

    32

    Long

    64

    Int

    32

    Short

    16

    Byte

    8

    注意,在Kotlin开发语言中,字符不属于数组。

    2.1.1.1. 文字常数

    对于整数值有下面几种文字常数:

    —— 十进制数:123

    —— 附加大写字母L标准长整数:123L

    —— 十六进制数:0x0F

    —— 二进制数:0b00001011

    注意:不支持八进制数字。

    Kotlin开发语言还支持通用的浮点数表示法:

    —— 默认是双精度:123.5,123.5e10

    —— 附加f或F表示单精度浮点数:123.5F

    2.1.1.2. 表示法

    在Java开发语言平台上,数字是作为JVM基本类型进行物理存在的,除非需要一个可null数字引用(如:Int?)或包含在泛型。后一种情况下,是将数字装箱的。

    注意数字装箱不保持一致性:

    1 val a: Int = 10000
    2 print(a === a) // 打印 'true'
    3 val boxedA: Int? = a
    4 val anotherBoxedA: Int? = a
    5 print(boxedA === anotherBoxedA) // !!!打印 'false'!!!

    而另一方面,却保持相等:

    1 val a: Int = 10000
    2 print(a == a) // 打印 'true'
    3 val boxedA: Int? = a
    4 val anotherBoxedA: Int? = a
    5 print(boxedA == anotherBoxedA) // 打印 'true'

    2.1.1.3. 显式转换

    由于不同的表示法,较小类型不是较大类型的子类型。如果是,就有下列麻烦了:

    1 // 假设代码,没有实际编译:
    2 val a: Int? = 1 // 装箱为Int (java.lang.Integer)
    3 val b: Long? = a // 隐含转换装箱为Long (java.lang.Long)
    4 print(a == b) // 令人惊讶! 当equals()检查其它部分不是Long,就打印"false"

    所以不仅仅是一致性,而且即使相当也会在此默默丢失一部分。

    这样,较小的类型不会隐含的转换为较大的类型。这就是说,如果没有进行明确的类型转换,Byte类型值是不能赋值给Int类型变量。

    1 val b: Byte = 1 // OK, 静态文字检查
    2 val i: Int = b // 错误

    可以进行明确(显式)的数字宽度转换:

    1 val i: Int = b.toInt() // OK: 显式宽度转换

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

    toByte(): Byte

    —toShort(): Short

    —toInt(): Int

    —toLong(): Long

    —toFloat(): Float

    —toDouble(): Double

    —toChar(): Char

    因为类型是从上下文推断,以及适当的转换重载了算术运算符,所以隐式转换缺位是很少引人注目的,例如:

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

    2.1.1.4. 运算

    Kotlin开发语言支持对数字标准的一套运算,它们被声明为相应类成员(但是,编译器优化调用的相应指令)。查看:运算符重载(5.6)。

    作为位运算,对于它们没有特殊特性(字符),仅仅命名函数使其能以中缀方式被调用,如:

    1 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

    2.1.2.   字符

    char类型表示字符。它们不能直接作为数组处理:

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

    字符文字是在单引号中:’1’,’ ’,’uFF00’。我们能够明确地转换字符到Int数字:

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

    在需要可null引用时,像数字、字符是被装箱。装箱操作是不保证一致性的。

    2.1.3.   布尔值

    Boolean类型表示布尔值,它有两个值:true和false。

    如果需要可null引用时,布尔值可以被装箱的。

    布尔值的内置的运算包括:

    — || – lazy分离 (注:这个“lazy”不知道怎样翻译好,就是 “或”为啥要这样?)

    — && – lazy连接

    — ! – 非

    2.1.4.   数组

    在Kotlin开发语言中,Array类表示数组,它有get和set函数(即通过操作符重载约定转成[]),有size属性,以及其他一些有用的成员函数:

    1 class Array<T> private constructor() {
    2   val size: Int
    3   fun get(index: Int): T
    4   fun set(index: Int, value: T): Unit
    5 
    6   fun iterator(): Iterator<T>
    7   // ...
    8 }

    可以用库函数arrayOf(),将数组各项的数值传递给它,来创建一个数组,如:arrayOf(1,2,3)创建数组[1,2,3]。或者,用arrayOfNulls()库函数创建一个指定尺寸(size)的数组,其元素均填充为null。

    另一种选择是用工厂函数获得数组尺寸,并且返回指定索引位置的数组元素的初始值:

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

    如上所述,[]操作符表示调用成员函数get()和set()。

    注意:与Java开发语言不同,在Kotlin开发语言中,数组是不变量。这意味着kotlin开发语言不允许赋值Array<String>到Array<Any>,这防止运行的可能的错误(但是,可以用Array<out Any>,查看:类型推测(3.7.2))。

    Kotlin开发语言也有专用类表示原始类型的数组,不需要装箱消耗:ByteArray、ShortArray、IntArray等等。这些类与Array类没有继承关系,但是它们有相同的一组方法和属性。它们中的每一个都有相应的工厂函数:

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

    2.1.5.   串

    String类型表示串。String是不可变的。串的元素是字符,可以用索引操作访问:s[i]。可以用for循环遍历一个串:

    1 for (c in str) {
    2   println(c)
    3 }

    2.1.5.1. 串文字

    Kotlin开发语言有两种串文字类型:包含转义字符的转义串和包含任意字符和新行符的原始串。转义串非常像Java开发语言的串:

    1 val s = "Hello, world!
    "

    转义可以用习惯的方法(用)实现。

    原始串由三引号(”””)定界的,包含非转义字符、新行符,以及其它任意字符:

    1 val text = """
    2   for (c in "foo")
    3     print(c)
    4 """

    2.1.5.2. 串模板

    串可以包含模板表达式,即:可计算的代码片段,其结果链接到串中。模板表达式以美元符号($)开始,和简单的名字构成:

    1 val i = 10
    2 val s = "i = $i" // 计算结果是 "i = 10"

    或是在大括号中的任意表达式:

    1 val s = "abc"
    2 val str = "$s.length is ${s.length}" // 计算结果是 "abc.length is 3"

    在原始串和转义串中,都支持模板。如果需要表达$字符文字,则可以用下列语法:

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

    2.2.  包

    一个源文件可以是从声明包开始的:

    1 package foo.bar
    2 
    3 fun baz() {}
    4 class Goo {}
    5 // ...

    源文件中的所有内容(如:类和函数)都包含在包的声明中。所以,在上面例子中,baz()的完整名称是foo.bar.baz,Goo的完整名称是foo.bar.Goo。

    如果源文件中没有指明包,则这个文件中的内容属于没有名称的“默认”包。

    2.2.1.   导入(import)

    除默认的import外,每个文件都可以有自己的import伪指令。Import的句法在语法(6.2)中描述了。

    我们既可以导入单个名称,如:

    1 import foo.Bar // Bar is now accessible without qualification

    也可以是范围内所有可访问的内容(包、类、对象等等):

    1 import foo.* // everything in 'foo' becomes accessible

    如果有命名冲突,可以在冲突项用as关键字重命名来消除:

    1 import foo.Bar // Bar可以访问
    2 import bar.Bar as bBar // bBar 表示 'bar.Bar'

    import关键字不限制导入的类;也可以用途导入其它声明:

    —— 顶层函数和属性;

    —— 在对象声明(3.12.2)中声明的函数和属性;

    —— 枚举常数(3.11);

    不像Java开发语言,Kotlin开发语言没有独立的“import static”句法;所有这些声明都是用常规的import关键字来导入。

    2.2.2.   顶层声明的可视范围

    如果顶层声明标注private,它是它所在文件的私有的(查看:可视性修饰符(3.4))

    2.3.  控制流

    2.3.1.   if表达式

    在Kotlin开发语言中,if是一个表达式,即:它返回一个值。由于在此规则下普通if运行的很好,因此没有三元运算符(?:else)。

     1 // 传统用法
     2 var max = a 
     3 if (a < b) 
     4   max = b 
     5  
     6 // 带else 
     7 var max: Int
     8 if (a > b) 
     9   max = a 
    10 else 
    11   max = b 
    12  
    13 // 作为表达式
    14 val max = if (a > b) a else b

    if分支可以是代码块,最后表达式是代码块的值:

    1 val max = if (a > b) { 
    2     print("Choose a") 
    3     a 
    4   } 
    5   else { 
    6     print("Choose b") 
    7     b 
    8   }

    如果用if作为表达式,而不是语句(例如,返回它的值,或赋值给变量),表达式要求有else分支。

    查看:if语法(6.2.3.4)

    2.3.2.   when表达式

    When替代了类似C开发语言的switch操作符。最简单形式如此:

    1 when (x) {
    2   1 -> print("x == 1")
    3   2 -> print("x == 2")
    4   else -> { // Note the block
    5     print("x is neither 1 nor 2")
    6   }
    7 }

    when将变量与其的所有分支顺序逐一匹配,直至找到条件相符的分支。when即可用作表达式,也可以用作语句,满足条件的分支值就是整个表达式的值。如果它用作语句,个别分支的值将被忽略。(就如同if,每个分支可以是一个代码块,代码块中最后的表达式值就是其值。)

    else分支等价与没有其它分支满足条件。如果when用作一个表达式,且编译器无法验证分支条件覆盖了所有的可能情况,则强制性要求else分支。

    如果多种情况都有相同的处理方法,也可以用逗号将分支条件组合起来:

    1 when (x) {
    2   0, 1 -> print("x == 0 or x == 1")
    3   else -> print("otherwise")
    4 }

    可以用任意表达式(不仅仅是常数)作为分支条件:

    1 when (x) {
    2   parseInt(s) -> print("s encodes x")
    3   else -> print("s does not encode x")
    4 }

    还可以用in或!in检查一个范围(5.2)或集合:

    1 when (x) {
    2   in 1..10 -> print("x is in the range")
    3   in validNumbers -> print("x is valid")
    4   !in 10..20 -> print("x is outside the range")
    5   else -> print("none of the above")
    6 }

    另一种情况,可以用is或!is检查特别类型。注意,由于智能转换(5.4),不需要任何额外的检查就可以访问类型的方法和属性:

    1 val hasPrefix = when(x) {
    2   is String -> x.startsWith("prefix")
    3   else -> false
    4 }

    when还可以用来替换if-else链。如果没有变量,分支条件就是简单的布尔表达式,且在when条件为true时,执行该分支:

    1 when {
    2   x.isOdd() -> print("x is odd")
    3   x.isEven() -> print("x is even")
    4   else -> print("x is funny")
    5 }

    查看:when语法(6.2.3.4.2.1)。

    2.3.3.   for循环

    for循环遍历提供的任何一个迭代器。句法如下:

    1 for (item in collection)
    2   print(item)

    循环体可以是一个代码块。

    1 for (item: Int in ints) {
    2   // ...
    3 }

    如前所述,for循环遍历提供的任何一个迭代器,即:

    —— 有成员iterator()或扩展函数iterator(),它返回类型:

     —— 有成员next()或扩展函数next(),和

     —— 有返回布尔类型的成员hasNext()或扩展函数hasNext()。

    所有这三个函数是需要作为操作符的。

    如果要利用索引遍历一个数组或列表,可以这样做:

    1 for (i in array.indices)
    2   print(array[i])

    注意,这句“遍历一个范围”是由编译器优化实现的,不需要产生额外的对象。

    或者,可以用withIndex库函数:

    1 for ((index, value) in array.withIndex()) {
    2     println("the element at $index is $value")
    3 }

    查看:for语法(6.2.3.3)。

    2.3.4.   while循环

    while和do…while都是如常规一样工作:

    1 while (x > 0) {
    2   x--
    3 }
    4 
    5 do {
    6   val y = retrieveData()
    7 } while (y != null) // y is visible here!

    查看:while语法(6.2.3.3)。

    2.3.5.   循环的中断和继续

    Kotlin开发语言支持循环中的传统break和continue操作符。查看:返回和跳转(2.4)。

    2.4.  返回和跳转

    Kotlin开发语言有三种结构化的跳转操作符:

    —— return。默认情况下,由最近的函数返回,或匿名函数的返回。

    —— break。终止最近一层循环。

    —— continue。继续最近一层循环的下一步。

    2.4.1.   中断和继续标签

    在Kotlin开发语言中,任何表达式都可以带标签。标签的格式是在标识符后跟@来表示,如:abc@,fooBar@都是合法的标签(查看:语法(6.2))。为了标记表达式,只需要在其前面加上标签即可:

    1 loop@ for (i in 1..100) {
    2   // ...
    3 }

    现在,就可以break或continue到标签了:

    1 loop@ for (i in 1..100) {
    2   for (j in 1..100) {
    3     if (...)
    4       break@loop
    5   }
    6 }

    带有标签的break跳转到标记loop之后的执行点。Continue继续进行标记loop的下一步。

    2.4.2.   在标签处返回

    Kotlin开发语言在函数体、局部函数和对象表达式中,允许函数嵌套。Return允许我们有外部函数返回。最重要的用例是由Lambda表达式返回。我们这样编写回调:

    1 fun foo() {
    2   ints.forEach {
    3     if (it == 0) return
    4     print(it)
    5   }
    6 }

    返回表达式是由最近函数返回,即:foo。(注意:这样对Lambda表达式仅支持非局部返回到内嵌函数(4.1.5)。)如果要从Lambda表达式返回,就需要标记它限制返回:

    1 fun foo() {
    2   ints.forEach lit@ {
    3     if (it == 0) return@lit
    4     print(it)
    5   }
    6 }

    现在,就仅从Lambda表达式返回。通常,最方便的是用隐含标签:这样标签与传递给Lambda表达式的函数同名。

    1 fun foo() {
    2   ints.forEach {
    3     if (it == 0) return@forEach
    4     print(it)
    5   }
    6 }

    或者,可以用匿名函数(4.2.3.3)替代Lambda表达式。在匿名函数中的return语句是从匿名函数自身返回。

    1 fun foo() {
    2   ints.forEach(fun(value: Int) {
    3     if (value == 0) return
    4     print(value)
    5   })
    6 }

    当返回一个值是,解析器优先给出恰当的返回,如:

    1 return@a 1

    就是“在标签@a处返回1”而不是“返回标签表达式(@a 1)”。

  • 相关阅读:
    MATLAB新手教程
    关于Core Location-ios定位
    《TCP/IP具体解释卷2:实现》笔记--IP的分片和重装
    利用JasperReport+iReport进行Web报表开发
    Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系
    Openfire开发配置,Openfire源码配置,OpenFire二次开发配置
    在Activity中为什么要用managedQuery()
    24点经典算法
    linux概念之时间与时区
    java实现第五届蓝桥杯大衍数列
  • 原文地址:https://www.cnblogs.com/figozhg/p/5140832.html
Copyright © 2011-2022 走看看