Kotlin学习系列——命名参数和默认参数

今天一起来看看Kotlin的命名参数和默认参数。

如果你学过Python,那你对这两个概念一定不陌生,那我们今天就来学习一波Kotlin中的默认参数和命名参数。

遇到的问题

为了说明命名参数和默认参数出现的必要性,我们先抛出一个问题,如何打印出一个集合,并且定制它的打印形式。在Java中我们最常用的思路就是重写toString()方法或者是写一个打印集合的工具类,比如下面的Java代码。

Java代码

public class Main {
    public static void main(String[] args) {
        List<String> mArrayList = new ArrayList<String>(){
            @Override
            public String toString() {
                StringBuilder stringBuilder = new StringBuilder();
                for (int i = 0; i < this.size(); i++) {
                    stringBuilder.append(this.get(i));
                    if (i < this.size() - 1){
                           stringBuilder.append(";");
                    }
                }
                return stringBuilder.toString();
            }
        };
        mArrayList.add("123");
        mArrayList.add("456");
        mArrayList.add("789");
        System.out.println(mArrayList);
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

上面我们是重写toString()方法,那我们看看在Kotlin中怎么做呢?我们先看看Kotlin中默认的打印样式。

Kotlin代码

fun main(args: Array<String>){
    val list = listOf<String>("123", "456", "789")
    println(list)
}

//打印结果:[123, 456, 789]
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我们现在就先用Kotlin来写一个定制打印集合样式的函数。

Kotlin代码

fun <T> joinToString(collection: Collection<T>, separator: String,
                     prefix: String, suffix: String): String{
    val result = StringBuilder(prefix)
    for ((index, element) in collection.withIndex()){
        if (index > 0){
            result.append(separator)
        }
        result.append(element)
    }
    result.append(suffix)
    return result.toString();
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

上面这种方法就是采用自己定义一个工具类,通过传入不同的参数来定制打印的样式。

命名参数

我们这里先来看看如何调用上面的函数,再说说存在的问题。

Kotlin代码

println(joinToString(list, ";", "(", ")"))
 
 
  • 1

显然这里有一个很不方便的地方,如果我们不借助于IDE的提示和查看方法定义,我们是很难看懂我们传递给函数的每个参数的具体含义,所以这个时候命名参数出现了。看这个名字就能知道,它是给参数命名,让我们对参数的传入和查看更加清楚,就像下面这样。

Kotlin代码

println(joinToString(list, ";", "(", ")"))
println(joinToString(collection = list, separator = ";", prefix = "(", suffix = ")"))
println(joinToString( separator = ";", collection = list, prefix = "(", suffix = ")"))
 
 
  • 1
  • 2
  • 3

看到了吗,我们给传入的每个参数前面加了一个名称,这样是不是很直观呢,而且由于这里的参数是用命名指定的,所以参数的顺序可以和定义函数的顺序不同,上面的三种方式都是可以正确调用的。
但是这里有一些注意事项:
1. 如果我们已经指定了一个参数的名称,那么这个参数其后的参数也必须指定名称,不让就会造成混淆,Kotlin编译器就不能明白你的意图。
2. 命名参数的形式只能用于Kotlin的函数,不能用于Java的函数,就像下面这样是错误的。

//Java代码
public class Main {
    public static void javaFun(String name){
        System.out.println(name);
    }
}

//Kotlin代码
fun main(args: Array<String>){
    //会报错[命名参数不能用于Java函数]
    println(Main.javaFun(name  = "bingjianit"))
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
默认参数

我们再回到文章开头的那个需求,我们希望我们使用Kotlin写的函数,可以在我们不传入分隔符是,默认使用”,”,在我们传入分隔符时使用我们传入的分隔符,也就是让我们的函数的某些参数具有默认值。其实同样的需求我们在Java中可以通过重载函数来实现,但是那会造成会出现很多个重载函数,在Kotlin中,我们可以通过默认参数来实现这个需求。

Kotlin代码

fun <T> joinToString2(collection: Collection<T>, separator: String = ",",
                     prefix: String = "[", suffix: String = "]"): String{
    val result = StringBuilder(prefix)
    for ((index, element) in collection.withIndex()){
        if (index > 0){
            result.append(separator)
        }
        result.append(element)
    }
    result.append(suffix)
    return result.toString();
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

上面的代码中我们为后面三个参数指定了默认值,当我们不传入值时,使用默认值,传入值时使用我们自己的参数,我们可以像下面一样调用。

Kotlin代码

//输出 [123,456,789]
println(joinToString2(list))
//输出 [123;456;789]
println(joinToString2(list, separator = ";"))
 
 
  • 1
  • 2
  • 3
  • 4

可以看出,我们这里其实是结合使用了默认参数和命名参数。

由于Kotlin与Java可以互操作,那么上面的函数在Java中怎么调用呢?由于Java中不支持默认参数,所以我们必须为函数传入每一个参数。就像下面这样:
我们在Str.kt文件中写了我们上面定义的有默认值的函数

//在Java中调用[必须传入全部的参数]
System.out.println(StrKt.joinToString2(mArrayList, ",", "{", "}"));
 
 
  • 1
  • 2

当然,如果你不想写这么繁琐,可以在Kotlin默认函数生成时添加一个@JvmOverloads注解,编译器就会自动为每个默认参数生成重载函数,就像下面这样

Kotlin代码

@JvmOverloads
fun <T> joinToString2(collection: Collection<T>, separator: String = ",",
                      prefix: String = "[", suffix: String = "]"): String{
    val result = StringBuilder(prefix)
    for ((index, element) in collection.withIndex()){
        if (index > 0){
            result.append(separator)
        }
        result.append(element)
    }
    result.append(suffix)
    return result.toString();
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

生成的Java重载函数如下
Java代码

public static <T> T joinToString2(Collection<T> collection);
public static <T> T joinToString2(Collection<T> collection, String separator);
public static <T> T joinToString2(Collection<T> collection, String separator, String prefix);
public static <T> T joinToString2(Collection<T> collection, String separator, String prefix, String suffix);    
 
 
  • 1
  • 2
  • 3
  • 4

这样我们在调用时就不需要传那么多参数了。

写在最后

Kotlin结合了多种语言的优秀特性,变成了一门简洁、精致的编程语言,并且还具备了和Java无缝的互操作性。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值