Kotlin系列(九):函数的定义及使用
- 更多分享:www.catbro.cn
一、前言:
- Kotlin的语法其实和Swift非常相似,Kotlin中的函数跟java不同,其将作为一级成员存在,如下带来的变化我们可以从下面的学习过程来体会。
- 以下我们将通过简单的demo来学习kotlin函数的编写及使用。
二、函数
定义函数的完整语法
[访问控制符] [修饰符] fun [<泛型标识符>] [扩展接收类型.]函数名([参数列表])[: 返回值类型]{ 函数体 }
语法说明:
- 我们定于函数的语法可以分为9部分
- 1、 [访问控制符]:可省略。
Kotlin 中的访问控制符有四个:public 、protected 、internal 、private,如果没有声明,则默认为 public。
- 2、 [修饰符]:可省略。
通过设置不同的修饰符,我们的函数将被添加不同的功能,例如: infix 和 inline
- 3、 fun:不可省略。
fun用来声明函数的关键字,是英语 Function(函数)的缩写。
- 4、 函数名:不可省略。
Kotlin的函数命名与 Java 方法命名一样,遵循骆峰式的命名法。
- 5、 [<泛型标识符>]:可省略。
与 Java 类似,如果返回值包含泛型,则需要在这里将函数标记为泛型函数。 例如: fun
singletonList(item: T): List = listOf(item),该函数的功能是输入一个元素,输出一个只包含这个元素的 List
- 6、 [扩展接收类型.]:可省略。
定义扩展函数时使用。扩展函数是我非常喜欢的一个特性,也是吸引我从Java转Kotlin的一个点。
- 7、 [参数列表]:可省略。
每个参数都使用“形参名: 形参类型”的形式,这里的形参类型是不能省略的。
- 8、 [: 返回值类型]:可省略,Kotlin可以自动推导,但还是推荐写上,提高代码阅读性。
返回值类型可以是 Kotlin 和 Java 中的引用数据类型。 如果一个函数没有返回值,则它的返回值类型是 Unit,一般会省略。例如: fun sayHello(name: String): Unit = println(" Hello,My Name is ${name}.")
- 9、 {函数体}:不可省略。
函数体定义函数的行为,如果函数体只有一句,可以写成“= 函数体”的形式(这时就像定义一个变量了)。
-
例如:
//简短的写法: fun add(a: Int, b: Int) = a + b //完整的写法: fun add(a: Int, b: Int): Int { return a + b }
三、函数的简单使用
1、函数的参数
-
函数参数的定义使用Pascal标记法, 也就是, name: type 的格式,多个参数之间使用逗号分隔,每个参数都必须明确指定类型.
-
定义一个函数,有两个int类型的参数,返回类型也是int
import org.junit.Test /** * Created by 安杰 on 2017/10/16. */class Demo1 { fun sum(a: Int, b: Int): Int { return a + b } @Test fun test1(): Unit { var result1 = sum(b = 2, a = 1); var result2: Int = sum(1, 2); println(result1) println(result2) } }
-
输出结果为:
3 3
- 代码分析:
- 第一个调用没有指定返回值类型,由Kotlin编译时自动推导。而且通过参数名指定传入的参数,好处是简单直接,参数不容易传错,而且参数位置可以随意改变。
- 第二个调用指定了返回值类型,没有指定参数名,所以参数需要按顺序传入。
定义带默认值的参数
-
函数参数可以指定默认值, 当参数省略时, 就会使用默认值. 与其他语言相比, 这种功能使得我们可以减少大 量的重载(overload)函数定义
-
参数默认值的定义方法, 在参数类型之后, 添加 = 和默认值.
-
我们只需要在参数后面加默认值即可,这个比java方便多了。
fun printSum1(a: Int = 1, b: Int = 1): Unit { println("sum of $a and $b is ${a + b}") } @Test fun test4(): Unit { var result = printSum1(); println(result) var result2 = printSum1(a = 3); println(result2) }
2、不定数量参数
-
如果在函数被调用以前,函数的参数(通常是参数中的最后一个)个数不能够确定,可以采用不定量参数方式,定义函数参数列表。比如在创建List时,创建前并不知道预添加至List中多少数据。
fun <T> asList(vararg args: T): List<T> { val result = ArrayList<T>() for (a in args) result.add(a) return result } @Test fun test9() { var result = asList(1,2,3,4) println(result) }
-
结果输出为:[1, 2, 3, 4]
-
代码解析:如上,我们调用时可以传入任意个数的参数。
-
注意事项:在一个函数中只可以声明一个参数为vararg。与Java不同的是,在Kotlin中标记为vararg的参数不一定是最后一个。如果标记为vararg的参数不是最后一个,那么vararg参数之后的其他参数, 可以使用命名参数语法来传递参数值, 或者, 如果参数类型是函数, 可以在括号之外传递一个 Lambda表达式.
-
示例代码如下
fun <T> asList(vararg args: T, last: T): List<T> { val result = ArrayList<T>() for (a in args) result.add(a) result.add(last) return result } @Test fun test9() { var result = asList(1, 2, 3, 4,last = 100) println(result) }
-
结果输出如下:[1, 2, 3, 4, 100]
-
当然,你也可以外部直接传入一个集合,传入形式为参数前加*
-
示例代码如下:
fun <T> asList(vararg args: T, last: T): List<T> { val result = ArrayList<T>() for (a in args) result.add(a) result.add(last) return result } @Test fun test9() { var result = asList(1, 2, 3, 4, last = 100) println(result) var temp = arrayOf(1,2,3,4,5,6); result = asList(*temp, last = 100) println(result) }
-
执行结果如下:
[1, 2, 3, 4, 100] [1, 2, 3, 4, 5, 6, 100]
三、返回值
1、Unit返回值
- 如果一个函数不返回任何有意义的结果值,那么它的返回类型为Unit .Unit 类型只有唯一的一个值Unit,在函数中,不需要明确地返回这个值
- 返回值为Unit,Unit为无类型,类似java中的void
- 对于返回值为Unit的函数,Unit可以省略
- 定义无返回值的函数
示例代码如下
fun printSum(a: Int, b: Int): Unit {
println("sum of $a and $b is ${a + b}")
}
@Test
fun test10(): Unit {
var result = printSum(b = 2, a = 1);
println(result)
}
- 执行结果为:
sum of 1 and 2 is 3 kotlin.Unit
2、单表达式函数
-
如果一个函数的函数体只有一个表达式,函数体可以直接写在 “=”之后。
-
示例代码如下
fun sum1(a: Int, b: Int):Int = a + b; @Test fun test(): Unit { var result = sum1(b = 2, a = 1); println(result) }
3、返回值类型自动推导
如果编译器可以推导出函数的返回值类型, 返回值的类型定义可以省略。
fun sum1(a: Int, b: Int) = a + b;
@Test
fun test() {
var result = sum1(b = 2, a = 1);
println(result)
}
4、明确指定返回值类型
如果一个函数体由多行语句组成的代码段,那么必须明确指定返回值类型,除非函数的的返回值为Unit。
四、函数的调用
1、传统用法
- 我们上面的例子都是使用函数的传统用法方式进行调用
- 调用类的成员函数时, 使用点号标记法(dot notation):
Sample().foo() // 创建一个 Sample 类的实例, 然后调用这个实例的 foo 函数
2、中缀标记法(Infix notation)
-
使用中缀标记法(infix notation)来调用函数, 但函数需要满足以下条件:
-
1、是成员函数, 或者是扩展函数
-
2、只有单个参数
-
3、使用 infix 关键字标记
-
示例代码如下:
class Person(var name: String, var age: Int) { infix fun printName(addr: String) { println("addr:$addr,name:$name"); } } @Test fun test10() { var p = Person(name = "anjie",age = 10); p printName ("guangzhou"); p printName "guangzhou" p.printName("guangzhou") }
-
运行结果为:
addr:guangzhou,name:anjie addr:guangzhou,name:anjie addr:guangzhou,name:anjie
- 我们可以看到,其等价与我们的.语法,目前我还没发现这个特性的优越性