文章目录

  • I . 函数类型
  • II . 带参数名的参数列表
  • III . 可空函数类型
  • IV . 复杂函数类型解读
  • V . 函数类型别名
  • VI . 带 接收者类型 的函数类型
  • VII . 函数类型实例化
  • VIII . 函数类型自动推断
  • IX . 带接收者的函数类型 与 不带接收者的函数类型 之间的转换
  • X . 函数类型变量调用

I . 函数类型


函数类型格式 : 圆括号中定义 参数类型列表 , 使用 -> 由参数列表指向返回值类型 , 表示接受 参数类型列表 中的参数 , 返回 返回值类型 的返回值 ;

( 参数类型列表 ) -> 返回值类型

① 参数列表 : 参数类型的列表 , 多个参数类型使用逗号隔开 ;

② -> 符号 : 由参数列表指向返回值类型 , 该符号用于分割参数类型列表 与 返回值类型 ;

③ 返回值类型 : 只有一个返回值类型 ;

④ 示例 : (Int, Int)->Int 参数类型 , 表示该参数传入两个 Int 类型的参数 , 返回 Int 类型返回值 ;

II . 带参数名的参数列表


1 . 函数类型参数名称 : 参数列表中可以只是参数类型 , 也可以加上参数的变量名称 , 参数名称可以用于说明参数的含义 , 增加函数类型的理解性 ;

2 . 只有参数类型的函数类型 : 参数列表中只有参数类型 ;

( 参数类型1 , 参数类型2 , … 参数类型n ) -> 返回值类型

3 . 有参数名称的函数类型 : 参数列表中每个元素都由 参数名称 : 参数类型 组成 , 多个列表元素使用逗号隔开 ;

( 参数名称1 : 参数类型1 , 参数名称2 : 参数类型2 , … 参数名称n : 参数类型n ) -> 返回值类型

4 . 带参数名称的函数类型示例 :

① 没有参数名的函数类型 : (Int , String)->String ;

② 有参数名的函数类型 : (age : Int , name : String)->String ;

III . 可空函数类型


1 . 函数类型根据是否可空分类 : 函数类型 与 普通变量类型一样 , 也分为可空类型 , 非空类型 两类 ;

2 . 默认非空类型 : 默认的函数类型都是非空类型 , 即函数定义时 , 需要对其进行初始化 , 或延迟初始化 ;

3 . 可空类型函数表示方法 : 可空的函数类型声明时 , 需要在函数类型外部加上括号 , 并在右侧添加 ? 可空符号 ;

( ( 参数列表 ) -> 返回值类型 ) ?

4 . 可空函数类型 与 非空函数类型 示例 :

① 非空函数类型 : (Int , String)->String , 普通的函数类型 , 默认就是非空的函数类型 ;

② 可空函数类型 : ( (Int , String)->String ) ? , 在非空函数类型基础上 , 外层添加括号 , 右侧添加 ? , 该函数类型就变成了可空函数类型 ;

IV . 复杂函数类型解读


1 . 复杂函数类型 :

① 参数返回值是普通类型 : 如果函数的参数类型和返回值类型都是普通的类型还好 , 解读起来不是很困难 ;

② 参数返回值是函数类型 : 如果函数类型的参数类型或返回值类型中有函数类型 , 即嵌套的函数类型 , 这些函数类型很复杂 ;

2 . 右箭头 -> 符号的结合性 : 该符号是右结合的 , 解读时 , 先将第一个 -> 符号右边的值理解成返回值 , 再逐步解析 :

( Int , String ) -> ( Float , Double ) -> String

① 分析外层函数类型 ( 函数类型 ) : 首先根据右结合性 , 从左到右开始解读 , 读取到第一个 -> 符号 , 说明这是一个函数类型 , ( Int , String ) 是参数列表 , ( Float , Double ) -> String 是返回值类型 ;

② 分析内层函数类型 ( 外层函数的返回值类型 ) : 然后继续分析 ( Float , Double ) -> String 类型 , 外层的函数类型的 返回值类型 是一个 函数类型 , 该函数类型参数列表是 ( Float , Double ) , 返回值是 String 类型 ;

③ 总结 : 这是函数类型的嵌套 , 外层函数类型的参数类型是 ( Int , String ) , 函数的返回值类型是 ( Float , Double ) -> String 是一个函数类型 ;

3 . 最佳实践 : 复杂的函数类型可读性很差 , 建议使用圆括号注明函数类型的结合性 , 层次 ;

( Int , String ) -> ( Float , Double ) -> String

这样表示虽然没有错误 , 也能读懂 , 但是该表示并不是一目了然 , 读懂理解也要花点时间 , 完全没有必要在代码中出脑筋急转弯题目 , 推荐加上圆括号 , 写成以下形式 :

( Int , String ) -> ( ( Float , Double ) -> String )

这样就可以一目了然 , ( Int , String ) 是参数列表 , ( ( Float , Double ) -> String ) 是返回值类型 , 该返回值类型是一个函数类型 ;

不推荐这种反人类的类型定义 , 建议还是以简洁为主 , 参考 C 语言的函数类型嵌套 int (*p) (int*, int (*f)(int*)) , C 语言的函数 + 指针类型嵌套 int (*(*p2)[5])(int*) , 这个需要根据复杂指针解读技巧慢慢解读 , 要花费很长时间才能搞懂 ;

V . 函数类型别名


使用 typealias 为函数类型声明一个别名 : 使用函数类型别名 , 能有效降低代码的复杂度 , 提高可读性 , 函数类型别名声明格式如下 :

typealias 别名 = 函数类型

代码示例 : 下面的示例中 , 为 (Int, Int) -> Int 函数类型声明了一个别名 , 该别名与函数类型的作用是一样的 ;

// 1 . 声明函数类型
typealias mathAdd = (Int, Int) -> Int// 2 . 为函数类型数理化
var add : mathAdd = {a : Int, b : Int -> a + b}// 3 . 为函数类型实例化
var add2 : (Int, Int) -> Int = {a : Int, b : Int -> a + b}fun main() {// 4 . 调用函数var result = add(1,2)println("$result")// 5 . 调用函数var result2 = add2(1,2)println("$result2")
}

VI . 带 接收者类型 的函数类型


1 . 带 接收者类型 的函数类型 : 函数类型 可以指定 接收者类型 , 格式如下 :

接收者类型.( 参数类型列表 ) -> 返回值类型

① 接收者类型 : 接收者类型 的含义是 , 这个接收者类型对象是 函数类型 实例的接收者 , 该对象拥有该函数 ;

② 上述的 函数类型 定义 表示 : 接收者类型 对象 , 调用 ( 参数类型列表 ) -> 返回值类型 函数类型的函数 , 传入 ( 参数类型列表 ) 类型的参数 , 将返回 “返回值类型” 的返回值 ;

③ 本质 : 实例化该 带接收者的函数类型 变量时 , 相当于为该接收者类型定义了一个扩展函数 ;

2 . 带接收者类型的函数类型示例 :

① 带接收者类型的函数类型 : String.(Int, Float)->String ;

② 示例类型解析 : 在 String 类型对象上 , 调用 (Int, Int)->String 类型的函数 , 在该函数中按照顺序传入 Int , Float 两个类型的参数 , 那么得到一个 String 类型的返回值 ;

VII . 函数类型实例化


函数类型 变量实例化 : 给 函数类型变量 进行赋值 , 可以赋值的类型有以下几种情况 ;

1 . Lambda 表达式 : 可以将 Lambda 表达式赋值给函数类型变量 ;

// 将 Lambda 表达式赋值给函数类型变量
var add1 : (Int, Int) -> Int = {a : Int, b : Int -> a + b}

2 . 匿名函数 : 匿名函数 可以直接赋值给 函数类型 变量 ;

// 将 匿名函数 赋值给函数类型变量
var add2 : (Int, Int) -> Int = fun (a : Int, b : Int) : Int {return a + b}

3 . 已声明的函数 : 已经声明的函数 , 可以直接赋值给函数类型变量 ; 这些函数可以是 顶层函数 , 成员函数 , 局部函数 , 扩展函数 ;

fun add(a : Int, b : Int) : Int {return a + b
}// 将顶层的 add 函数赋值给 add3 函数类型变量 :: 用于获取顶层定义的函数
//  如果获取 类中定义的函数 , 可以使用 类名::函数名 获取
var add3 : (Int, Int) -> Int = ::add

4 . 函数变量 : 已经声明的函数类型属性 , 可以是顶层属性 , 成员属性 , 扩展属性 ;

// 将 Lambda 表达式赋值给函数类型变量
var add1 : (Int, Int) -> Int = {a : Int, b : Int -> a + b}// 将已经定义好的函数类型变量重新赋值给 另外一个函数类型明亮
var add4 : (Int, Int) -> Int = add1

5 . 函数类型 派生类 : 函数类型可以看做一个接口 , 类可以实现该接口 , 在实现类中实现具体的函数操作 , 该 函数类型接口的实现类 , 可以赋值给函数类型变量 ;

class AddOperation : (Int, Int) -> Int{override fun invoke(p1: Int, p2: Int): Int {return p1 + p2}
}// 将 函数类型 接口派生类对象赋值给 函数类型变量
var add5 : (Int, Int) -> Int = AddOperation()

VIII . 函数类型自动推断


1 . 变量类型推断 : Kotlin 中的变量类型可以不用显示声明 , 可以根据其赋值的类型进行智能类型推断 ;

2 . 函数变量类型推断 : 函数类型变量也具有智能类型推断的性质 ;

var add = {a : Int, b : Int -> a + b}

上面的代码中省略了函数类型变量的函数类型 , 其赋值的 Lambda 表达式类型是 (Int, Int) -> Int 类型的 , 因此推断出 add 变量的函数类型是 (Int, Int) -> Int 类型的 ;

IX . 带接收者的函数类型 与 不带接收者的函数类型 之间的转换


带接收者的函数类型 , 可以转换为 不带接收者的函数类型 , 转换规则是 , 带接收者的函数类型的接收者 , 可以转换为不带接收者类型的第一个参数 ;

下面的两个函数类型是等价的 :

① 自带接收者的函数类型 : String.( Int ) -> String

② 不带接收者的函数类型 : ( String, Int ) -> String

带接收者函数类型 与 不带接收者函数类型 转换代码示例 :

// 字符串 "abc" 调用该函数 , 传入 2 参数 , 结果是 "abcabc"
var fun1 : String.( Int ) -> String = {times : Int -> this.repeat(times)}// 这是将 接收者 设置成了第一个参数 , 将 String.( Int ) -> String 函数类型的变量 fun1 赋值给了
//  ( String, Int ) -> String 函数类型变量
var fun2 : ( String, Int ) -> String = fun1fun main() {//"Tom".fun1(2) = TomTomprintln("\"Tom\".fun1(2) = ${"Tom".fun1(2)}")//fun2("Jerry", 2) = JerryJerryprintln("fun2(\"Jerry\", 2) = ${fun2("Jerry", 2)}")
}

① 自带接收者的函数类型 : fun1 是带接收者的 函数类型 变量 , 其类型是 String.( Int ) -> String 类型 ;

② 不带接收者的函数类型 : fun2 是不带接收者的 函数类型变量 , 其类型是 ( String, Int ) -> String 类型 ;

③ 互相赋值 : 将 fun1 变量赋值给 fun2 变量 , 赋值成功 , 说明这两个变量类型是相同的 ;

④ 调用函数 : 分别调用 fun1 和 fun2 函数 , 调用结果相同 ;

执行结果 :

"Tom".fun1(2) = TomTom
fun2("Jerry", 2) = JerryJerry

X . 函数类型变量调用


函数类型变量调用 :

① invoke 调用 : 可以通过 函数类型变量名.invoke(参数列表) 调用该函数 ;

② 直接调用 : 也可以通过 函数类型变量名(参数列表) 直接调用该函数 , 将该变量名称当做函数名称来使用 ;

【Kotlin】函数类型 ( 函数类型 | 带参数名称的参数列表 | 可空函数类型 | 复杂函数类型 | 带接收者函数类型 | 函数类型别名 | 函数类型实例化 | 函数调用 )相关推荐

  1. java 获取参数的类型_java反射获取方法名称,参数类型

    package com.mysec.reflex; import java.lang.reflect.Constructor; import java.lang.reflect.Field; impo ...

  2. java1.8中javassist获取接口函数参数名称

    前提条件 在java8中要获取类函数参数名称必须在编译时增加参数 编译器时加上-parameters参数 具体内容详见 java1.8获取类和接口函数参数名称 尝试使用javassist获取接口函数名 ...

  3. python笔记之函数参数(缺省参数,命名参数,不定长参数)

    缺省参数 函数中定义带有初始值的形参 参数调用时,缺省参数可传,可不传 缺省参数一定在参数列表的最后面 缺省参数的数量没有限制 def x_y_sum(x,y=20): #缺省参数要在参数列表的最后p ...

  4. MyBatis参数名称解析器-ParamNameResolver解析

    ParamNameResolver ParamNameResolver是一个参数名解析器,负责把方法的参数按顺序解析出来并进行标注 主要用来处理接口形式的参数,最后会把参数处放在一个map中 map的 ...

  5. JAVA可变参数的使用(数据类型... 参数名称)

    JAVA可变参数的使用(数据类型- 参数名称) 需求 假设需要定义一个方法求和,该方法需要灵活的完成如下需求: 1.计算2个数据的和. 2.计算3个数据的和. 3.计算n个数据的和. 或者可以支持不接 ...

  6. TP5.1使用pgsql报错“没有匹配指定名称和参数类型的函数. 您也许需要增加明确的类型转换”的解决办法...

    我遇到的错误 大致是这样的: [ info ] [ DB ] INIT pgsql [ error ] [10501]SQLSTATE[42883]: Undefined function: 7 错误 ...

  7. TP5使用pgsql报错“没有匹配指定名称和参数类型的函数. 您也许需要增加明确的类型转换”的解决办法...

    错误信息如下 [ info ] [ DB ] INIT pgsql [ error ] [10501]SQLSTATE[42883]: Undefined function: 7 错误: 函数 tab ...

  8. TP5使用pgsql报错“没有匹配指定名称和参数类型的函数. 您也许需要增加明确的类型转换”的解决办法

    转载https://www.cnblogs.com/gremlin/p/9449825.html 若有侵权,请联系删除! 错误信息如下 [ info ] [ DB ] INIT pgsql [ err ...

  9. python函数用法详解2(变量的作用域(全局变量、局部变量)、共享全局变量、函数返回值、函数的参数(位置参数、关键字参数、默认参数、不定长参数)、拆包、交换变量值、引用、可变和不可变类型)

    1. 变量作⽤域         变量作⽤域指的是变量⽣效的范围,主要分为两类:局部变量和全局变量. 局部变量         定义在函数体内部的变量,即只在函数体内部⽣效. def testA(): ...

最新文章

  1. 【blade利刃出鞘】一起进入移动端webapp开发吧
  2. AI:2020年6月23日北京智源大会演讲分享之AI创业专题论坛——09:10-10:00 李开复教授《AI赋能时代的创业》
  3. 用Location对象和history对象修改页面url
  4. ubuntu 将某个目录下的文件复制到_命令行 将多个特定文件从一个文件夹复制到另一个文件夹...
  5. ICC_lab总结——ICC_lab6:版图完成
  6. oracle10数据库链接失败,oracle 10g Enterprise Manager 无法连接到数据库实例分析
  7. 关于推荐的一个算法工程师访谈,有一些内容值得看看
  8. pipeline 发布war包
  9. “土豪机”8848出新品 手机数据备份保险箱1699起
  10. Centos6.6部署Redis集群
  11. Educoder 机器学习 神经网络 第四关:使用pytorch搭建卷积神经网络识别手写数字
  12. PHP一个文件内多个php代码段的写法
  13. Machine Learning: A Probabilistic Perspective——Chapter 1
  14. java制作进度条,Java制作进度条
  15. 如何在一张ppt中插入多张图片并能依次播放
  16. 手游测试之《弱网测试》
  17. 基础练习 Sine之舞
  18. mysql数据库md5密码替换_MD5 加密的密码在数据库重置
  19. Win10笔记本电脑连接不上WiFi的解决办法
  20. 【java基础06:数据类型】及拓展、转义字符、计算机二进制的表现形式

热门文章

  1. Ubuntu ADSL 拨号上网时断时续问题
  2. 从零开始学习Kafka
  3. 八皇后问题 (递归 搜索)
  4. 关于排版中经常见的问题的解决方法
  5. Linuxnbsp;JDK1.4卸载与1.6的安装
  6. SQLite主键自增需要设置为integer PRIMARY KEY
  7. C# 正则表达式小结
  8. 一年以来我最好的创意
  9. Angular 一个简单的指令实现 阻止事件扩散
  10. Python函数01/函数的初识/函数的定义/函数调用/函数的返回值/函数的参数