重拾Kotlin(1)-变量、数据类型、函数

1、Hello World

按照国际惯例,学习一门新的语言一般都是从“Hello World”开始的,在这里也不例外,先看下 Java 中的 main 方法如何用 Kotlin 来表示java

fun main(args: Array<String>) {
    println("Hello World")
}
复制代码

从这里能够看出 Kotlin 相比 Java 有几点不一样git

  1. 用关键字 fun 来声明一个函数
  2. 参数类型写在变量名以后
  3. 函数能够定义在文件的最外层,不须要把它放在类中
  4. 数组就是类。和 Java 不一样,Kotlin 没有声明数组类型的特殊语法
  5. 使用 println 代替了 System.out.println ,这是 Kotlin 标准库提供的对 Java 标准库函数的封装
  6. 能够省略代码结尾的分号

此外,Kotlin 的最新版本已经能够省略 main 方法的参数了github

2、变量

在 Java 中,大部分的变量是可变的,意味着任何能够访问到这个变量的代码均可以去修改它。而在 Kotlin 中,变量能够分为 可变变量(var)不可变变量(val) 两类编程

声明变量的关键字有两个:数组

  • val(value)——不可变引用。使用 val 声明的变量不能在初始化以后再次赋值,对应的是 Java 中的 final 变量
  • var(variable)——可变引用。var 变量的值能够被改变,对应的是 Java 中的非 final 变量

不可变变量在赋值以后就不能再去改变它的状态了,所以不可变变量能够说是线程安全的,由于它们没法改变,全部线程访问到的对象都是同一个,所以也不须要去作访问控制,开发者应当尽量地使用不可变变量,这样可让代码更加接近函数式编程风格安全

此外,在 Kotlin 中一切都是对象,没有像 Java 中那样的原始基本类型,但 byte、char、integer、float 或者 boolean 等类型仍然有保留,可是所有都做为对象存在ide

看如下例子函数式编程

fun main(args: Array<String>) {
    //只读变量即赋值后不能够改变值的变量,用 val 声明
    //声明一个整数类型的不可变变量
    val intValue: Int = 100

    //声明一个双精度类型的可变变量
    var doubleValue: Double = 100.0
}
复制代码

在声明变量时咱们一般不须要指明变量的类型,这能够由编译器根据上下文自动推导出来函数

fun main(args: Array<String>) {
    //在声明变量时咱们一般不须要指明变量的类型,这能够由编译器根据上下文自动推导出来
    val intValue = 100
    var doubleValue = 100.0

    //若是只读变量在声明时没有初始值,则必须指明变量类型
    val intValue2: Int
    intValue2 = 10
}
复制代码

3、数据类型

3.一、基本数据类型

与 Java 不一样,Kotlin 并不区分基本数据类型和它的包装类,在 Kotlin 中一切都是对象,能够在任何变量上调用其成员函数和属性学习

对于基本类型,Kotlin 相比 Java 有几点特殊的地方

  • 数字、字符和布尔值能够在运行时表示为原生类型值,但对开发者来讲,它们看起来就像普通的类
  • Kotlin 对于数字没有隐式拓宽转换,而在 Java 中 int 能够隐式转换为 long
  • 在 Kotlin 中字符不能视为数字
  • Kotlin 不支持八进制
//在 Kotlin 中,int、long、float 等类型仍然存在,可是是做为对象存在的

    val intIndex: Int = 100
    //等价于,编译器会自动进行类型推导
    val intIndex = 100

    //数字类型不会自动转型,必需要进行明确的类型转换
    val doubleIndex: Double = intIndex.toDouble()
    //如下代码会提示错误,须要进行明确的类型转换
    //val doubleIndex: Double = intIndex

    val intValue: Int = 1
    val longValue: Long = 1
    //如下代码会提示错误,由于二者的数据类型不一致,须要转换为同一类型后才能进行比较
    //println(intValue == longValue)

    //Char 不能直接做为数字来处理,须要主动转换
    val ch: Char = 'c'
    val charValue: Int = ch.toInt()
    //如下代码会提示错误
    //val charValue: Int = ch

    //二进制
    val value1 = 0b00101
    //十六进制
    val value2 = 0x123
复制代码

此外,Kotlin 的可空类型不能用 Java 的基本数据类型表示,由于 null 只能被存储在 Java 的引用类型的变量中,这意味着只要使用了基本数据类型的可空版本,它就会被编译成对应的包装类型

//基本数据类型
    val intValue_1: Int = 200
    //包装类
    val intValue_2: Int? = intValue_1
    val intValue_3: Int? = intValue_1
    //== 比较的是数值相等性,所以结果是 true
    println(intValue_2 == intValue_3)
    //=== 比较的是引用是否相等,所以结果是 false
    println(intValue_2 === intValue_3)
复制代码

若是 intValue_1 的值是100,就会发现 intValue_2 === intValue_3 的比较结果是 true,这就涉及到 Java 对包装类对象的重复使用问题了

3.二、Any 和 Any?

Any 类型是 Kotlin 全部非空类型的超类型,包括像 Int 这样的基本数据类型

若是把基本数据类型的值赋给 Any 类型的变量,则会自动装箱

val any: Any = 100
    println(any.javaClass) //class java.lang.Integer
复制代码

若是想要使变量能够存储包括 null 在内的全部可能的值,则须要使用 Any?

val any: Any? = null
复制代码

3.三、Unit

Kotlin 中的 Unit 类型相似于 Java 中的 void,能够用于函数没有返回值时的状况

fun check(): Unit {

}

//若是返回值为 Unit,则能够省略该声明
fun check() {

}
复制代码

Unit 是一个完备的类型,能够做为类型参数,但 void 不行

interface Test<T> {
    fun test(): T
}

class NoResultClass : Test<Unit> {
    
    //返回 Unit,但能够省略类型说明,函数也不须要显式地 return 
    override fun test() {

    }

}
复制代码

3.四、Nothing

Nothing 类型没有任何值,只有被当作函数返回值使用,或者被当作泛型函数返回值的类型参数使用时才会有意义,能够用 Nothing 来表示一个函数不会被正常终止,从而帮助编译器对代码进行诊断

编译器知道返回值为 Nothing 类型的函数从不正常终止,因此编译器会把 name1 的类型推断为非空,由于 name1 在为 null 时的分支处理会始终抛出异常

data class User(val name: String?)

fun fail(message: String): Nothing {
    throw IllegalStateException(message)
}

fun main(args: Array<String>) {
    val user = User("leavesC")
    val name = user.name ?: fail("no name")
    println(name) //leavesC

    val user1 = User(null)
    val name1 = user1.name ?: fail("no name")
    println(name1.length) //IllegalStateException
}
复制代码

4、函数

Kotlin 中的函数以关键字 fun 做为开头,函数名称紧随其后,再以后是用括号包裹起来的参数列表,若是函数有返回值,则再加上返回值类型,用一个冒号与参数列表隔开

//fun 用于表示声明一个函数,getNameLastChar 是函数名
        //空括号表示该函数无传入参数,Char 表示函数的返回值类型是字符
        fun getNameLastChar(): Char {
            return name.get(name.length - 1)
        }
复制代码
//带有两个不一样类型的参数,一个是 String 类型,一个是 Int 类型
        //返回值为 Int 类型
        fun test1(str: String, int: Int): Int {
            return str.length + int
        }
复制代码

此外,表达式函数体的返回值类型能够省略,返回值类型能够自动推断。对于有返回值的代码块函数,必须显式地写出返回类型和 return 语句

//getNameLastChar 函数的返回值类型以及 return 关键字是能够省略的
        //返回值类型能够由编译器根据上下文进行推导
        //所以,函数能够简写为如下形式
        fun getNameLastChar() = name.get(name.length - 1)
复制代码

若是无返回值,则能够声明 Unit ,也能够省略 Unit

如下三种写法都是等价的

fun test(str: String, int: Int): Unit {
            println(str.length + int)
        }

        fun test(str: String, int: Int) {
            println(str.length + int)
        }

        fun test(str: String, int: Int) = println(str.length + int)

复制代码

重拾 Kotlin 系列文章目录: 重拾 Kotlin

相关文章
相关标签/搜索