• Kotlin基础——函数、变量、字符串模板、类


    变量

    Kotlin和Java一样是静态语言,所有表达式类型在编译期已经确定,public为默认可见性

    变量由 var/val+变量名[: 数据类型][?][ = 值] 组成,如

    var a = 1
    
    var b: Int
    b = 3
    
    var s: String? = null
    
    val language = arrayListOf("java")
    language.add("Kotlin")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 无需显示声明每个变量的类型,自动类型推导
    • 若变量未初始化则需要显示指定类型
    • ?标记变量可以为空,若无则不可为空
    • val为不可变变量,初始化后不能再次赋值,对应Java的final,但其指向的对象可以改变

    函数

    函数组成为 fun 函数名(参数名: 参数类型, …): 返回值{}

    fun max(a: Int, b: Int): Int {
        return if (a > b) a else b
    }
    
    • 1
    • 2
    • 3

    上面称为代码块函数体,当函数体由单个表达式构成时,可简化为表达式函数体(自动会推导出返回类型)

    fun max(a: Int, b: Int) = if (a > b) a else b
    
    • 1

    默认参数和命名参数

    如定义一个格式化输出集合的函数

    fun  joinToString(
        collection: Collection,
        separator: String,
        prefix: String,
        postfix: String
    ): String {
        val result = StringBuilder(prefix)
        for ((index, element) in collection.withIndex()) {
            if (index > 0)
                result.append(separator)
            result.append(element)
        }
        result.append(postfix)
        return result.toString()
    }
    
    
    val list = listOf("1", "2", "3")
    println(joinToString(list, "-", "[", "]"))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在常规调用中,必须按照参数顺序给定参数,通过带默认值的参数可以省略后面的参数传递,默认参数被编码到被调用的函数内部

    fun  joinToString(
        collection: Collection,
        separator: String = "",
        prefix: String = "",
        postfix: String = ""
    ): String {
        val result = StringBuilder(prefix)
        for ((index, element) in collection.withIndex()) {
            if (index > 0)
                result.append(separator)
            result.append(element)
        }
        result.append(postfix)
        return result.toString()
    }
    
    println(joinToString(list, "-"))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Java需要显式传递所有参数,若需要调用上面的函数,可以用@JvmOverloads注解,会生成

    String joinToString(Collection collection, String separator, String prefix, String postfix);
    String joinToString(Collection collection, String separator, String prefix);
    String joinToString(Collection collection, String separator);
    String joinToString(Collection collection);
    
    • 1
    • 2
    • 3
    • 4

    如果使用命名参数可以省略中间的参数,按照任意顺序给定参数

    println(joinToString(list, prefix = "[", postfix = "]"))
    
    • 1

    可变参数

    由vararg定义,如下为listOf源码

    public fun  listOf(vararg elements: T): List = if (elements.size > 0) elements.asList() else emptyList()
    
    • 1

    可通过展开运算符*,把数组元素作为单独的参数来调用

    fun main(args: Array) {
        val list = listOf("args1", *args)
        println(list)
    }
    
    • 1
    • 2
    • 3
    • 4

    中缀调用和解构声明

    中缀调用为特殊的函数调用,如下是一个简单的to()函数定义,会生成一个Pair对象

    infix fun Any.to(other: Any) = Pair(this, other)
    
    • 1

    使用的时候会自动解构声明

    val (number, name) = 1 to "one"
    
    println("$number")
    println("$name")
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    map的生成和遍历使用到了中缀调用

    val map = mapOf(1 to "one", 7 to "seven")
    
    for ((number, name) in map) {
        println("$number:$name")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    顶层函数和属性

    如新建一个test.kt文件,创建max()方法,其不属于任何类

    package com.demo.demo1
    
    fun max(a: Int, b: Int): Int {
        return if (a > b) a else b
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    会被编译Java的静态函数

    public class TestKt {
        public static int max(int a, int b) {
            if (a > b)
                return a;
            else
                return b;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    如果需要修改顶层函数生成的类的名称,可以在包名前添加注解

    @file:JvmName("MyTest")
    
    package com.demo.demo1
    
    fun max(a: Int, b: Int): Int {
        return if (a > b) a else b
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    同理,test.kt文件存放属性

    package com.demo.demo1
    
    var a = 0
    val b = 1
    const val c = 2
    
    • 1
    • 2
    • 3
    • 4
    • 5

    会被编译Java的静态域

    public class TestKt {
        public static int a = 0;
        public static int b = 1;
        public static final int c = 2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    扩展函数和属性

    把要扩展的类/接口的名称放到即将添加的函数前面,如下扩展String类新增lastChar()方法

    • 可省略this
    • 能访问被扩展类的public方法和属性
    • 不在同一包的文件需要import扩展函数,若出现命名冲突,可以使用as重命名
    • 不能被子类重写
    • 如果扩展函数和成员函数有相同签名,会优先调用成员函数
    fun String.lastChar(): Char = this.get(this.length - 1)
    
    println("Kotlin".lastChar())
    
    • 1
    • 2
    • 3

    在Java中访问扩展函数(放在test.kt)

    TestKt.lastChar("Kotlin");
    
    • 1

    如下定义扩展属性,因为String内容不可变,所以没有setter()

    val String.lastChar: Char
        get() = this.get(length - 1)
    
    var java.lang.StringBuilder.lastChar: Char
        get() = get(length - 1)
        set(value: Char) {
            setCharAt(length - 1, value)
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    当Java中访问扩展属性(放在test.kt),需要显示调用getter()

    TestKt.getLastChar("Java");
    
    • 1

    局部函数

    如下类,在存储时需要验证各个字段的有效性

    class User(val id: Int, val name: String, val address: String)
    
    fun saveUser(user: User) {
        if (user.name.isEmpty()) {
            throw IllegalArgumentException("can't save user ${user.id} : empty name")
        }
    
        if (user.address.isEmpty()) {
            throw IllegalArgumentException("can't save user ${user.address} : empty address")
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    局部函数可使用可使用外层函数的参数,如下抽取为通用的验证方法

    class User(val id: Int, val name: String, val address: String)
    
    fun saveUser(user: User) {
        fun validate(value: String, field: String) {
            if (value.isEmpty()) {
                throw IllegalArgumentException("can't save user ${user.id} : empty $field")
            }
        }
        validate(user.name, "name")
        validate(user.address, "address")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    若User和saveUser为系统的对象,我们不能对其原方法改动,可将其作为扩展函数

    class User(val id: Int, val name: String, val address: String)
    
    fun saveUser(user: User) {
        //原生方法
    }
    
    fun User.validateBeforeSave(value: String, field: String) {
        if (value.isEmpty()) {
            throw IllegalArgumentException("can't save user ${id} : empty $field")
        }
    }
    
    fun MySaveUser(user: User) {
        user.validateBeforeSave(user.name, "name")
        user.validateBeforeSave(user.address, "address")
        saveUser(user)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    字符串

    字符串模板

    可在字符串中通过$引用变量

    fun main(args: Array) {
        val name = if (args.size > 0) args[0] else "Kotlin"
        println("Hello,$name")
    }
    
    • 1
    • 2
    • 3
    • 4

    还可以用${}引用表达式

    fun main(args: Array) {
        if (args.size > 0) {
            println("Hello,${args[1]}")
        }
    }
    
    fun main(args: Array) {
        println("Hello,${if (args.size > 0) args[0] else "Kotlin"} ")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    正则表达式

    如下Java代码返回null,因为split()接收的是一个正则表达式,点会被作为任意字符

    String s = "12.34";
    System.out.println(Arrays.toString(s.split(".")));
    
    • 1
    • 2

    而在Kotlin中,可显式声明正则

    val s = "12.34"
    println(s.split("\\.".toRegex()))
    
    • 1
    • 2

    三重引号

    三重引号可避免转义字符

    println("""C:\\Users\\User\\Desktop""")
    
    • 1

    还可以处理前缀及其前面的空格(默认为|),如下用.当前缀,

    println(""".A
                .B
                .   C
            """.trimMargin("."))
    
    • 1
    • 2
    • 3
    • 4

    上面输出

    A
    B
       C
    
    • 1
    • 2
    • 3
  • 相关阅读:
    Python:为何成为当下最热门的编程语言?
    Git实战之git客户端上传文件到github
    想学嵌入式开发,薪资怎么样?
    vue打开一个新窗口
    GO—函数
    finalshell上传文件失败的解决方法
    token验证的方法
    用户运营,如何多方面拉新?
    如何一起修改多张图片大小?一键修改多张图片尺寸的技巧
    浮点数在内存中的存储
  • 原文地址:https://blog.csdn.net/qq_35258036/article/details/133951022