目录

Kotlin系列(九):函数的定义及使用

一、前言:

  • Kotlin的语法其实和Swift非常相似,Kotlin中的函数跟java不同,其将作为一级成员存在,如下带来的变化我们可以从下面的学习过程来体会。
  • 以下我们将通过简单的demo来学习kotlin函数的编写及使用。

二、函数

定义函数的完整语法

[访问控制符] [修饰符] fun [<泛型标识符>] [扩展接收类型.]函数名([参数列表])[: 返回值类型]{ 函数体 }

语法说明:

  • 我们定于函数的语法可以分为9部分
  • 1、 [访问控制符]:可省略。

Kotlin 中的访问控制符有四个:publicprotectedinternalprivate,如果没有声明,则默认为 public。

  • 2、 [修饰符]:可省略。

通过设置不同的修饰符,我们的函数将被添加不同的功能,例如: infixinline

  • 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

  • 我们可以看到,其等价与我们的.语法,目前我还没发现这个特性的优越性