• Kotlin基础数据类型和运算符


    原文链接 Kotlin Types and Operators

    Kotlin新一代的基于JVM的静态多范式编程语言,功能强大,语法简洁,前面已经做过Kotlin的基本的介绍,今天就来深入的学习一下它的数据类型和运算操作符。

    数据类型

    与大部分语言不同的是,在Kotlin中一切皆为对象(Everything is an object),它没有像Java/C++那样,是没有基础数据类型(primitive types)的,都是对象,因此也不会有像Java那样的box和auto box的麻烦。box和autobox对于单独使用基础数据类型时没啥问题,比如一个方法add(Integer),会进行自动装箱和拆箱。但如果在集合中使用就不一样了,比如array of int与array of Integer是完全不同的数据类型,以及list of int与list of Integer也是完全不同的数据类型,在这些场景里就会相当麻烦,要进行转换,详细可以参考这篇文章

    变量类型的声明

    类型是放在变量之后,这样可以先强调变量的名字,后关注其类型,如:

    var count: Int
    var message: String
    fun double(x: Int): Int {
          return x + x
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    类型推断

    虽然Kotlin是静态强类型语言,也就是说在编译的时候,编译器必须知道你的数据是什么类型的,这与Java和C++等是一样的,但并不意味着你必须为每个变量声明它的类型。变量的声明,是告诉编译器有一个什么类型的变量,以及叫什么,就比如在函数中的参数列表,就是变量的声明;而变量的定义,则是在声明的同时,要给变量赋值。

    那么,当定义变量的时候,编译器是能够直接推断出来它的类型的,这个时候就可以省去类型的声明,Kotlin语言力求简洁,凡是能推断出变量的类型时都可以省去类型的声明,如定义变量的时候,如在lambda中,或者在函数的返回值中。

    val PI = 3.14 // Double
    val PI: Double = 3.14 // 与上面的效果一样
    
    • 1
    • 2

    数字类型(Numbers)

    数字类型与大部分语言一样,特别的,它与Java语言是一样的,都是有符号的,即数字最高数位代表符号。

    整数

    与Java语言一样,有四大整数具体类型,8位的Byte,16位的Short,32位的Int以及64位的Long。它们的范围如下:

    TypeSize(bits)Min valueMax value
    Byte8-128127
    Short16-32768 (-2^15)32767 (2^15 - 1)
    Int32-2,147,483,648 (-2^31)2,147,483,647 (2^31 - 1)
    Long64-9,223,372,036,854,775,808 (-2^63)9,223,372,036,854,775,807 (2^63 - 1)

    当然了,每个类型都有其最大值最小值的常量可以直接引用,不用自己手动写。另外需要注意的是非10进制的字面常量都是二的补码形式,并不是直观的二进制,详细的可以参考另外一篇文章

    浮点数

    有Float和Double,它们的定义如下:

    TypeSize (bits)Significant bitsExponent bitsDecimal digits
    Float322486-7
    Double64531115-16

    #### 字面常量(Literals) 字面常量是指直接写在代码中的数字,默认的是Int和Double,如果需要指定类型,可以用标记或者给变量指定类型,如:
    val one = 1 // Int
    val threeBillion = 3000000000 // Long, exceeding Int, so it is Long
    val aLong = 1L // mark it as Long
    val oneByte: Byte = 1 // Byte
    val e = 2.7182818284 // Double
    val eFloat = 2.7182818284f // Float, actual value is 2.7182817
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    常见的语法糖:

    • 浮点数可以用乘方形式如123.5e10
    • 可以下划线(underscore)来加强可读性,如1_000_000
    • 16进制用0x打头,如0xFF_AB
    • 二进制用0b打头,如0b1101_1111

    布尔类型(Booleans)

    字符类型(Characters)

    用两个单引号来表示,如val ch = ’ ’

    需要注意因为字符是对象,所以不能直接与整数进行比较,需要转化为整数,这点不像Java,在Java中字符是可以直接与整数比较的。

            val map = CharArray(26)
            var index = 0
            for (ch in key) {
                if (!ch.isLetter()) {
                    continue
                }
                if (map[ch - 'a'].toInt() == 0) {
                    map[ch - 'a'] = 'a' + index
                    index++
                }
            }
    
            return message.map { if (it.isLetter()) map[it - 'a'] else it }
                        .joinToString("")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    字符串类型(Strings)

    可以视为字符的数组,是一个不可变对象(immutable object),用两个双引号来表示,如

    val message = "Hello, world"
    
    • 1

    字符串拼接用加号+

    val name = "John"
    val message = "Hello" + name
    
    • 1
    • 2

    当然了,直接用加号拼接效率不好,一般情况下可以直接用字符串模板更好一些。

    字符串模板

    这是一个强大且方便的内置功能,相当于简化版本的String.format,可以在字符串用**美元符$**来引用一个变量的值,如果是有方法调用或者运算或者成员引用等情况可以加花括号:

    val name = "John"
    val message = "Hello, $name"
    println("Length is ${name.length}")
    
    • 1
    • 2
    • 3
    字符遍历

    与Java不同的是,字符串在Kotlin里面更像是字符数组,或者说一个列表,因此可以直接遍历:

    val mesage = "The quick fox jumps over the lazy dog"
    for (ch in message) {
         println(ch)
    }
    
    • 1
    • 2
    • 3
    • 4

    in是一个强大的操作符,可以用于集合的遍历。另外,字符串可以像列表一样进行函数式的操作,如判断是否包含某个字符:

    if (message.any {it == ch}) {
       println("$ch is in $message")
    }
    
    • 1
    • 2
    • 3

    数组类型(Arrays)

    数组Array是一个具体类型为T的数组,这是通用的数组,另外还有一种就是基本数组类型数组,我们分别来看一下

    通用对象数组 Array

    这是适用于所有对象的数组,有两种构造方式,一是通过arrayOf(),直接传入数组的具体值,另外就是用构造方法Array(size)

    val heights = arrayOf(240, 360, 480, 640)
    val classes = arrayOf("John", "Harden", "Kevin", "Stephen")
    val guards: Array<String> = Array(5)
    guards[0] = "Stephen"
    guards[1] = "Kevin"
    
    • 1
    • 2
    • 3
    • 4
    • 5

    还有一种用lambda方式来构造数组,可以非常方便的实现数组的定义:

    val asc = Array(5) { i -> (i * i).toString() }
    // asc = ["0", "1", "4", "9", "16"]
    
    • 1
    • 2

    需要注意的是这里的类型T都是对象。但其实,对于基础类型的数组,如果都box成为对象效率并不高,虽然Kotlin中并没有真的基础数据类型,但涉及到数组这种批量的数据时,使用基础类型能提升很大的效率,因此还有专门用于基础类型的数组类型。

    基础类型数组 IntArray和FloatArray

    其实有很多,基础的类型都有IntArray, ByteArray, ShortArray, FloatArray, DoubleArray。而且需要注意的是Array与IntArray是两个数组类型,它们并不一样,这个区别与Java中的Integer[]和int[]是类似的。而且IntArray与Array也没什么关系,也不是什么继承关系。但是它们表现出来的使用方法是一样的。

    val heights = intArrayOf(240, 360, 480, 640)
    val squares = IntArray(5) { i -> i * i } // [0, 1, 4, 9, 16]
    val arr = IntArray(5) { 42 } // [42, 42, 42, 42, 42]
    val bundle = arrayOf(intArrayOf(1080, 720), intArrayOf(1920, 1080)) // bundle type is Array
    
    • 1
    • 2
    • 3
    • 4

    运算操作符

    运算操作符与大部分语言是一样的。

    算术运算符

    也即是常规的算术操作符,+(加) -(减)*(乘) /(除) %(取模),这些都是二元操作符,也就是需要两个操作数才能使用。

    还有单元操作符,如自增++自减–,当然也分前置和后置,区别与Java/C++中一样。

    操作符与**赋值符=**可以配合一起使用,如a += b等同于a = a + b,a /= c等同于 a = a / c

    逻辑运算符

    双元操作符: && 逻辑与,|| 逻辑或,它们的操作数必须 是布尔型,且返回值也是布尔。

    与其他语言一样,这两个操作符是short-circiut的或者说是lazy的,也即a && b,如果a是false,那就不去管b了,因为不影响结果;a || b也一样,如果a是true就不去管b了。

    还有单元操作符**! 逻辑非**。一个有意思的地方在于,逻辑非可以与一些操作符合起来使用,而不是直接写在表达式之外,比如,下面两种写法等效:

    if (!(a in asc)) {...}
    if (a !in asc) {...}
    if (b !is Array) {...}
    if (!(b is Array)) {...}
    
    • 1
    • 2
    • 3
    • 4

    位运算符

    位运算符比较特殊,与大部分语言不一样。

    移位
    操作符含义示例说明
    shr向右移位a shr 1把a向右移1位
    shl向左移位a shl 1a向左移1位
    ushr无符号向右移位a ushr 1(包含符号位)向右移1位
    按位逻辑运算
    操作符含义示例说明
    and按位与a and 1a与1按位与
    or按位或a or 1a与1按位或
    xor按位异或a xor 1a与1按位异或
    inv按位取反inv(a)把a按位取反

    这些操作符看起来可能比较怪,然后更怪异的是位运算操作符不能与**赋值符=**一起使用,只能这样写:

    a = a or b
    c = c xor (1 shl 3)
    
    • 1
    • 2

    事实上位运算不是操作符,它们是一种函数,叫做infix函数,简写了把括号省略了,看起来就像操作符一样,但它们并不是操作符。

    运算符重载

    与C++中的运算符重载类似,Kotlin中支持运算符重载,本质上它们都是对象定义的方法,但支持重载为运算符。

    比如说加法,a + b,可以写成方法调用的形式a.plus(b);b or c等同于b.or©,!a等同于a.not()。

    运算符的优先级

    尽管是有默认的优先级的,但强烈建议使用括号以减少歧义和增强可读性,更可以避免一些难以察觉的Bug。

    参考资料

    原创不易,打赏点赞在看收藏分享 总要有一个吧

  • 相关阅读:
    JAVA栈、堆、方法区
    array_map与array_walk的用法与区别详解
    服务器环境搭建
    虚拟机构建单体项目及前后端分离项目
    声学——声源定位阅读笔记
    【快应用】deeplink 3种跳转格式现象总结
    Linux+qt:获取.so自身的路径(利用dladdr)
    Qtday1
    c#开发和学习(c#编写windows服务)
    TiDB 工具下载
  • 原文地址:https://blog.csdn.net/hitlion2008/article/details/134255031