Kotlin认识与基础语法

219 阅读7分钟

Kotlin认识与基础语法

1.认识Kotlin

2010年大名鼎鼎的JetBrains公司(知名的InteliJ IDEA就是他们的产品之一),产生创造Kotlin的想法,从那之后开始了Kotlin的语言设计。2017年Google I/O大会之后,Kotlin成为了Android平台上官方支持的语言,被称之为“更好的Java”。

特性

  • 与现有的Java代码完全兼容
  • 在很大程度上实行了类型推导,Java 10才支持局部变量的推导
  • 放弃static关键字,但又引入了object,可以直接使用它声明单例,Java则必须依靠构建所谓的“单例模式”才能等效表达。
  • 具有一些“特殊类”,比如Data Classes(数据类),Sealed Classes(密封类),我们可以构建更深程序上的代数数据类型,结合when表达式来使用。

强大的生态

  • Android开发 我们不公可以用Kotlin调用现成的Java库,而且还有Google提供的Kotlin扩展库。
  • 服务端开发 这是JVM语言最大的一个应用领域,自然也是Kotlin发挥的舞台。在Android支持Kotlin之后,Spring Framework 5也对它敞开了怀抱。基于Kotlin更自然的函数式特性,用Spring进行Web开发会在某些方面比Java有更好的体验。
  • 前端开发 Kotlin还有两个强大的特性:dynamic类型及类型安全的构建器。前者实现其与JavaScript互通,后者可以帮助开发者构建可靠的HTML页面。你可以尝试使用Kotlin构建UI。
  • 原生环境开发 Kotlin Native离开了JVM,可以直接编译成机器码供系统环境运行。

KMM

Kotlin Multiplatform Mobile,Kotlin基于上述的生态特性,可实现跨平台开发,它注重的是将与平台无关的代码通用化,共用一份Kotlin代码实现,生成多个平台的原生产物;至于平台特性相关的代码(包括UI)建议使用各自平台的原生方案,各自写一份代码解决。

2. 基础语法

  • 类型推导
//变量声明
val str:String = "I am kotlin"

//类型推导
val string = "I am kotlin"
val int = 1314
val long = 1314L
val float = 13.14f
val double = 13.14
val doubleLong = 10.1e6

//打印以下的变量类型,如println(string.javaClass.name)
println(string.javaClass.name) //java.lang.String
println(int.javaClass.name) //int
println(long.javaClass.name) //long
println(float.javaClass.name) //float
println(double.javaClass.name) //double
println(doubleLong.javaClass.name) //double
  • 声明函数的返回值类型
//声明函数,Unit类型,类似于java中的void关键字,1个int类型参数
fun sum(x:Int):Unit{
    val y = x + 1
}

//声明函数,int类型返回值,两个int类型参数
fun sum(x:Int,y:Int):Int {return x + y}

//上述函数的另一种实现,用等号定义一个函数,表达式函数体,与之相对的称之为代码块函数体
fun sum1(x:Int,y:Int):Int = x + y
fun sum2(x:Int,y:Int) = x + y

//在一些类似递归的复杂情况下,即使用表达式定义函数,必须显示声明类型
fun foo(n:Int):Int = if (n == 0) 1 else n * foo(n - 1)
  • val与var
//val:引用不可变
//尽可能采用val、不可变对象及纯函数来设计函数
//作为防御性编码思维模式,更安全可靠,因为变量的值永远不会在其他地方被改变(反射技术除外,适合并发编程)
val x = intArrayOf(1,2,3)
//x = intArrayOf(2,3,4)  //Error:Val cannot be reassigned,类似于java的final,只读变量

x[0] = 3 //引用虽然不可更改,值是可以改变的
println(x[0]) //输出3

//var 变量
var y = 5
y += 5
println(y)

var r = cal(listOf(1,2,3))
println(r)

fun cal(list:List<Int>):Int{
    //[1,2,3],el为集合中的元素
    //res = 0
    //res *= el
    //res += el
    return list.fold(0) {
        res,el -> res * el + el
    }
} 
  • 函数类型
fun main(){

    val fn = fun04(10)
    fn(20)

    val fn05 = object : (Int) -> Int{
        override fun invoke(p: Int): Int {
            return p * 5
        }
    }
    fun05(fn05)
}

//函数类型

fun fun01(x:Int):Int{
    //(Int)-> Int
    // 1个int类型参数,返回值类型为Int
    return x + 5
}

fun fun02(){
    //()-> Unit
    // 没有参数,返回值类型为Unit
}

fun fun03(x:Int,s:String):Unit{
    //(Int,String) -> Unit
    //1个int类型参数,1个String类型参数,返回值类型为Unit
}

//(Int)->((Int)->Unit)
//(Int)->Int->Unit
//1个int参数,返回值类型为(Int)->Unit
fun fun04(x:Int):((Int) -> Unit){
    return object : (Int) -> Unit{
        override fun invoke(p: Int) {
            println(x + p)
        }
    }
}

//((Int)->Int)->Unit
//1个(Int)->Int类型参数,返回值类型为Unit
fun fun05(fn:(Int)->Int):Unit{
    val r = fn(10)
    println(r)
}
  • 方法和成员引用
fun main(){
    //方法引用,类的构造方法引用
    val getBook = ::Book
    //输出Dive into Kotlin
    println(getBook("Dive into Kotlin").name)

    //成员引用
    val bookNames = listOf(Book("Thinking in Java"),Book("Dive int Kotlin")).map(Book::name)
    //输出[Thinking in Java, Dive int Kotlin]
    println(bookNames)
}
  • Lambda
fun main(){
    //语法糖Lambda,下面3种是等价的
    val sum1 : (Int,Int) -> Int = { x:Int,y:Int -> x + y}

    val sum2  = {x:Int,y:Int -> x + y}

    val sum3 : (Int,Int) -> Int = { x,y -> x + y}

    val foo = { x:Int->
        val y = x - 2
        y  //相当于return y
    }

    println(foo(10))  //打印输出8

    listOf(1,2,3).forEach{ p(it) } //打印输出123

    listOf(1,2,3).forEach { it -> p(it) } //等价于上面的代码

    listOf(1,2,3).forEach { p(it).invoke() } //invoke方法
}

fun p(int :Int) = {
    print(int)
}

//Function类型
//Kotlin在JVM层设计了Function类型(Function0,Function1...Function22)来兼容Java的Lambda表达式
//每个Function类型都有一个invoke方法
interface Function1<in P1,out R> : kotlin.Function<R>{
    fun invoke(p1:P1):R
}
  • 函数,lambda和闭包
//代码块函数体在返回非Unit类型的值,必须带return
fun sumReturn1(x:Int,y:Int):Int {
    return x + y
}

//单表达式函数体,可以省略return
fun sumReturn2(x:Int,y:Int) = x + y

val methodDo1 = { x:Int,y:Int -> x + y} //methodDo1.invoke(1,2)或methodDo1(1,2)

fun methodDo2(x:Int) = {y:Int -> x + y} //methodDo2(1).invoke(2)或methodDo2(1)(2)

fun main(){
    //Kotlin的闭包不仅可以访问外部变量,还能修改其值
    var sum = 0
    listOf(1,2,3).filter { it > 0 }.forEach { sum+=it }
    println(sum)
}
  • 柯里化、扩展函数
//sumFun01与sumFun02是等价的
fun sumFun01(x:Int) = { y:Int -> x + y}

//柯里化的方式实现
fun sumFun02(x:Int) :(Int) -> Int{
    return {y:Int -> x + y }
}

fun sumFun03(x:Int,y:Int,z:Int) = x + y + z

fun sumFun04(x:Int) = {y:Int ->{z :Int -> x + y + z}}

fun funBlock(block:() -> Unit){
    block()
}

fun funBlock(x:Int,block: (Int) -> Unit){
    block(x)
}

fun main(){
    println(sumFun01(1)(2))
    println(sumFun02(1)(2))

    println(sumFun03(1,2,3))
    println(sumFun04(1)(2)(3))


    funBlock(object : () -> Unit {
        override fun invoke() {
            println("block")
        }
    })

    //与上面的方法调用相同,采用柯里化的方式
    funBlock { println("block") }

    funBlock(10,object :(Int) -> Unit{
        override fun invoke(p1: Int) {
            println(p1)
        }
    })

    //与上面的方法调用相同,采用柯里化的方式
    funBlock(10){
        println(it)
    }

    val a = A()
    a.a()
    a.b()

}

//扩展函数
fun A.b(){
    println("b")
}

class A{
    fun a(){
        println("A")
    }
}
  • 面向表达式编程
//Lambda表达式,类型为(Int) -> Int
{x:Int -> x + 1}

//函数体表达式,类型为(Int) -> Unit
fun (x : Int){println(x)}

//if-else表达式,类型为Int
if (x > 1) x else 1
        
//复合表达式,try表达式和if表达式结合使用        
val res:Int? = try{
    if (result.success){
        jsonDecode(result.response)
    }else{
        null
    }
}   catch (e:JsonDecodeException){
    null
}  

fun main(){
    //?: Elvis运算符或null合并运算符
    val maybeInt:Int? = null
    maybeInt ?:1 //maybeInt值为1
}
  • 枚举类
//枚举类
enum class Day1{
    MON,
    TUE,
    WEN,
    THU,
    FRI,
    SAT,
    SUN
}

enum class Day2(val day:Int){
    MON(1),
    TUE(2),
    WEN(3),
    THU(4),
    FRI(5),
    SAT(6),
    SUN(7);

    fun getDayNumber():Int{
        return day
    }
}

fun main(){
    val day = Day2.FRI
    println(day.getDayNumber())
}
  • when表达式
//when表达式
fun main(){
    val a = 10
    when (a){
        1 -> 1
        2 -> 2
        else -> 3
    }
    
    when{
        a == 1 -> 5
        a > 1 -> 6
        else -> 7
    }
}

fun whenMethod(fail:Boolean,score:Int) = when{
    score == 60 -> 60
    score in 61..79 -> 80
    fail -> 50
    else -> 100
}
  • for循环和范围表达式
//for循环和范围表达式
fun main(){
    //其中1..10就是范围表达式,"abc" .. "xyz"
    for (i in 1 .. 10)  println(i)

    for (j : Int in 1..10){
        println(j)
    }

    //步长为2
    for (i in 1 ..10 step 2) println(i)

    //倒序
    for (i in 10 downTo  1 step 2) println(i)

    //1至9,不包含10
    for (i in 1 until 10) println(i)

    "a" in listOf("a","b","c") //是否在其中,true

    "a" !in listOf("b","c") //是否不在其中,true

    "kot" in "abc" .."xyz"

    val array = arrayOf(10,20,30)
    for (c in array) println(c) //遍历数组

    //遍历数组,同时获取索引与值
    for ((index,value) in array.withIndex()){
        println("index = $index,value = $value")
    }
}
  • 中缀表达式
//中缀表达式,标准库里的to
//infix fun<A,B> A.to(that:B):Pair<A,B>
//A 中缀方法 B
//中缀函数必须是某个类的扩展函数或成员方法,且只能有一个参数,参数不能有默认值
class Person{
    infix fun called(name: String){
        println("name = $name")
    }
}


//vararg代表可变参数
fun printLetters(vararg letters:String,count:Int):Unit{
    print("$count letters are ")
    for (letter in letters) print(letter)
}

fun main(){
    mapOf(
        1 to "one",
        2 to "two"
    )

    val p = Person()
    p.called("Jane")
    p called "Angel"

    val letters = arrayOf("A","B","C")
    //*g来传入可变参数
    printLetters(*letters, count = 3)
}