Kotlin学习笔记三:函数

Kotlin学习笔记

Kotlin学习笔记一:Kotlin基础
Kotlin学习笔记二:Kotlin的类型系统
Kotlin学习笔记四:类,对象,接口
Kotlin学习笔记五:Lambda编程
Kotlin学习笔记六:运算符重载及其他约定

函数

命名参数

调用函数时,可以显式标明参数的名称。如果指定了一个参数的名称,那它其后的参数都要标明名称,命名参数的顺序与函数定义的顺序不一定要一致

fun test(v1:Int, v2:Int, v3:Int) {
    println("v1=$v1, v2=$v2, v3=$v3")
}

fun main(args : Array<String>) {
    test(1, 2, 3)
    test(1, v2=3, v3=4)
    test(1, v3=4, v2=5)
//    test(1, v3=4, 3) //编译出错
}

调用非Kotlin函数时不能使用命名参数。比如:Java函数,Android框架函数


默认参数值

Java 的另 个普遍存在的问题是, 些类的重载函数实在太多了。这些重载,原本是为了向后兼容 ,方便这些 API 的使用者,又或者出于别的原因,但导致的最终结果是一致的 :重复。这些 参数名和类型被重复了一遍又一遍

在Kotlin 中,可以在声明函数的时候 ,指定参数的默认值,这样就可以避免创
建重载的函数。也可以用命名参数指定具体参数值

fun test(v1:Int=3, v2:Int=4, v3:Int=5) {
    println("v1=$v1, v2=$v2, v3=$v3")
}

fun main(args : Array<String>) {
    test()
    test(8)
    test(9, 10)
    test(1, 2, 3)
    test(v2=3)
    test(v1=4, v3=6)
}

注意,参数的默认值是被编码到被调用的函数中,而不是调用的地方。如果你改变了参数的默认值并重新编译这个函数,没有给参数重新赋值的调用者,将会开始使用新的默认值。

Java函数没有默认值,从Java调用Kotlin默认参数的函数时,必须指定全部的参数。如果需要从 Java 代码中做频繁的调用,而且希它能对 Java 的调用者更简便,可以用@JvmOverloads 注解它。这个指示编译器生成 Java 重载函数,从最后一个开始省略每个参数。


顶层函数和属性

可以消除静态工具类。把函数接放到代码文件的顶层,不用从属于 任何的类 。这些放在文 件顶层的函数依然是包内的成员,如果你需要从包外访问它,则需要 import 但不再需要额外包一层

/* Join.kt */
package strings
fun joinToString (... ) : String { ... }

/* Java */
package strings;
public class JoinKt {
public static String joinToString(..){...}

顶层函数对应用的就是Java的public static 函数。Kotlin文件对应的Java类是:文件名Kt,然后就可以像调用静方法一样调用。比如JoinKt.joinToString

可以在文件的开头,也就是声明包的前面加 @file:JvmName ("StringFunctions"),改变生成的Java文件名字。

顶层属性和顶层函数一样都是声明在类外部。默认情况下,顶层属性是private static,是通过访问器暴露给 Java 使用的(如果是 val 就只有 geter ,如果是 var 就对应 geter setter)。如果想用Java的public static,则用 const val 声明变量

var counter = 1
const val test:Int = 1

扩展函数和属性

给现有类库增加函数,和普通的函数声明类似,在函数名加上你要扩展的类名和 .

fun String.lastChar(): Char = this.get(this.length - 1)

前面的String称为接收者类型,调用这个函数的那个对象称为接收者对象,即后面的this
,this也可以省略,可以直接访问衩扩展的类的方法和属性。

注意: 扩展函数并不允许你打破它的封装性。和在类内部定义的方法不同的是 ,扩展函数不能访问私有的或者是受保护的成员

对于定义的扩展函数,它不会自动地在整个项目范围内生效 相反,如果你要使用它,需要进行导入,就像其他任何的类或者函数

可以使用关键字 as 修改导入的类或者函数名称,解决命名冲突的问题:
import strings.lastChar as last

实质上,扩展函数是静态函数,它把调用对象作为了它的第一个参数 调用扩展函数,不会创建适配的对象或者任何运行时的额外消耗这使得从 Java 中调用 Kotlin 的扩展函数变得非常简单:调用这个静态函数,然后把接收者对象作为第一个参数传进去即可

扩展函数并不是类的一部分,它是声明在类之外的。尽管可以给基类和子类都分别定义一个同名的扩展函数,当这个函数被调用时,它是由该变量的静态类型所决定的,而不是这个变量的运行时类型。

注意: 如果一个类的成员函数和扩展函数有相同的签名,成员函数往往会被
优先使用

扩展属性和扩展方法声明方式类似,也是在普通的变量声明前加上类名和.,它也一个接收者类型和接收者对象。扩展属性没有任何状态,因为没有合适的地方来存储它,本质上还是扩展方法,只不过使用了一种短语法

val String.lastChar: Char
    get() = get(length - 1)

var StringBuilder.lastChar: Char
    get () = get(length - 1)
    set(value: Char) {
        this.setCharAt(length - 1, value)
    }

注意: 当从Java中访问扩展属性的时候,应该显式地调用它的getter函数。比如
StringUtilKt.getLastChar ("Java")


可变参数和中缀调用

可变参数用 vararg 声明,相当于Java中的参数后跟三个点…

fun <T> listOf(vararg values: T): List<T> {...}

/* Java */
public <T> List<T> listOf(T... values){...}

Kotlin和Java 之间的另一个区别是,当需要传递的参数己经包装在数组中时,调用该函数的语法Java中,可以按原样传递数组,而Kotlin则要求你显式地解包数组,以便每个数组元素在函数中能作为单独的参数来调用。这个功能被称为展开运算符,而使用的时候,不过是在对应的参数前面放*号

fun main(args : Array<String>) {
    arrayListOf(*args)
}

注意: 在Kotlin 1.3版本上不用展开,直接传递数组即可

中缀调用不是一种内置结构,而是一种特殊的函数调用。在中缀调用中,函数名称直接放在目标对象名称和参数之间。

 val map= mapOf(1 to "one", 7 to "seven ", 53 to "fifty-three")
    
    1.to("one")
    1 to "one"

中缀函数用 infix 修饰,只可修饰成员函数和扩展函数,并且函数只能有一个参数

infix fun String.test(a :Int)=null

解构声明在循环的时候见过(list.withIndex)。解构是用类实例去初始化变量。

/* to 函数在Kotlin库的声明,它返回的是一个Pair对象 */
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)

val (key, value) = 1 to "one"

字符串和正则表达式处理

Java的 String.split 函数把传入的字符串当正则处理,而Kotlin正相反,它把参数当普通的字符串处理,仅当需要正则的时候,需要显式的创建一个Regex类型

println ("12.345-6.A". split (" \\. !".toRegex ()))

三重引号不会对字符串中的特殊字符转义,也会保留换行符,TAB等


局部函数

局部函数是在一个函数的内部定义函数

解决重复代码的一个方法就是用Extract Method方式重构代码,但这会生成许多小的方法,很多只有一个调用的点。Kotlin提供了一个更整洁的方案,可以在函数中嵌套这些提取的函数,这样既可以获得所需的结构,也无须额外的语法开销。

局部函数可以访问所在函数中的所有参数和变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值