2024年10月kotlin匿名函数(Kotlin返回与跳转)

 更新时间:2024-10-12

  ⑴kotlin匿名函数(Kotlin返回与跳转

  ⑵Kotlin返回与跳转

  ⑶借鉴kotlin中文站Kotlin有三种结构化跳转表达式:所有这些表达式都可以用作更大表达式的一部分:这些表达式的类型是Nothing类型。在Kotlin中任何表达式都可以用标签(label来标记。标签的格式为标识符后跟符号,例如:abc、fooBar都是有效的标签。要为一个表达式加标签,我们只要在其前加标签即可。现在,我们可以用标签限制break或者continue:标签限制的break跳转到刚好位于该标签指定的循环后面的执行点。continue继续标签指定的循环的下一次迭代。Kotlin有函数字面量、局部函数和对象表达式。因此Kotlin的函数可以被嵌套。标签限制的return允许我们从外层函数返回。最重要的一个用途就是从lambda表达式中返回。回想一下我们这么写的时候:这个return表达式从最直接包围它的函数即foo中返回。(注意,这种非局部的返回只支持传给内联函数的lambda表达式。如果我们需要从lambda表达式中返回,我们必须给它加标签并用以限制return。现在,它只会从lambda表达式中返回。通常情况下使用隐式标签更方便。该标签与接受该lambda的函数同名。或者,我们用一个匿名函数替代lambda表达式。匿名函数内部的return语句将从该匿名函数自身返回请注意,前文三个示例中使用的局部返回类似于在常规循环中使用continue。并没有break的直接等价形式,不过可以通过增加另一层嵌套lambda表达式并从其中非局部返回来模拟:当要返一个回值的时候,解析器优先选用标签限制的return,即意为“返回到a”,而不是“返回一个标签标注的表达式(a)”。

  ⑷为什么很多程序员不用switch,而是大量的ifelseif

  ⑸我个人觉得switch其实非常多余。

  ⑹大部分场景,都是到个可能分支,用个ifelse就可以了,除非有个以上分支,太多else显得不好看,才考虑用switch.

  ⑺switch限制多。switch必须是常量变量。if后面可以写任意表达式。

  ⑻用法复杂,case后面要么break,要么return,要是不写,居然还会继续执行剩下的分支,对于新手来说分分钟掉坑。

  ⑼写法上其实也不比ifelse优雅简洁,switchxxxcasexxxx….

  ⑽所以,switch徒增复杂性,真的不怎么实用。

  ⑾如果有种switch的可能性,有个值需要被处理,怕是你们说的这些个switch的好处就完全消失了,预期平均每次要比较次,个值,总计要比较亿次,不知道你们的CPU是啥主频能扛得住这个计算量,针对这种情况的终极武器还是hash,根据不同的语言,hash的value可以是匿名函数,可以是接口的不同实现,用hash来快速确定处理算法,而不是switch

  ⑿答案:主要因为switch不适合业务系统的实际复杂需求,业务不断的变更迭代,一更改需求,条件的复杂度高了,switch无力处理。

  ⒀那么什么时候适合switch,它的场景是:基于单一变量的值(如枚举,这样的可读性比if条件更清晰。

  ⒁从上面的场景来看,实在太局限,我来简单说一下它的一些缺点吧:

  ⒂现实的业务场景很复杂,条件不单一,一旦需求变更,维护代码相当崩溃。

  ⒃switch经常忘记写break,估计很多人一不小心就忘记写了。如果你看过google的代码规范,你会发现,Google对switch的要求非常多。

  ⒄switch的封装才更灵活

  ⒅其实switch有人还在用也有一部分是历史原因,但是随着科技的发展,原有的设计以及落后了。

  ⒆有些编程语言,如Python都没有switch这种语法。当然也有部分新语言Golang和Kotlin还是继承下来,但是又把switch包装了一下,去掉了令人误会的语法,这才让switch变得灵活起来了。如果不封装,很难用。

  ⒇通过上面描述的缺点也就是if语句更灵活的地方,根据业务进行逻辑条件编写,可维护性高。同时只要写的代码质量高,可读性也就会更高。

  ⒈现实的业务实际是很复杂的,我也不建议一定要用大量的if……elseif,而是应该尽早返回来减少嵌套,这样增加了可读性以及降低维护的成本。

  ⒉从C/C++来看,当分支较多且switch要比较的值是连续的话,执行速度远远远远快于if,因为switch是直接跳到目标代码执行的,而if则需要执行很多条语句,慢的不是一点点,一般编译器会根据分支数量和比较的值是否连续生成不同汇编代码,如果编译器判定不能提升速度的话,switch生成的汇编代码和if是一模一样的没有任何区别。

  ⒊至于很多人不用switch我觉得可能是:

  ⒋为了方便写代码,思维习惯随手就用if写了;

  ⒌可能根本就不懂为什么要用switch吧。

  ⒍作为程序员来说,我更喜欢switch的结构,更直观更容易找到相应的代码块。不过为什么很多程序员不用Switch,而是使用大量的if...elseif的结构,甚至像Python已经不支持原生Switch语法了?

  ⒎这个原因很简单,因为switch语法结构最后编译还是通过if...elseif来完成代码的,所以从效率角度来说和if...elseif一样的。但是switch对比条件比较单一,绝大多数支持switch的编程语言都支持等于比较,也就是说变量只能等于case中的条件才会执行代码块。但是现实情况中,对比条件绝大多数比单一等于运算要复杂得多,因此很多程序员就直接使用if...elseif。但是if...elseif的结构,后期维护起来会比较不清晰,毕竟没有Case...Break那么直观。但是添加一些注解应该还是能解决这个问题的。

  ⒏所以,我现在能使用Switch的时候还是会使用switch,毕竟后期代码维护起来方便点。不过更多时候还是用if...elseif。

  ⒐送大家以下java学习资料

  ⒑我曾经接手过一份代码,遇到过一个三十几个ifelse套ifelse的模块。

  ⒒心理骂骂咧咧谁他喵写的这玩意,然后开始review历史。

  ⒓大致情况是这样的:第一个程序员写下这段代码时,只有两个ifelse;后来开始逐渐加需求,先是一个、两个,随后量变引起质变,于是逻辑分支快速扩张。

  ⒔这个时候已经没有人愿意去重构成switch或是其他什么设计模式了,毕竟复杂度摆在那里,万一崩了还得背锅。

  ⒕三四个程序员接手这段代码之后,就变成我现在这种局面了。

  ⒖第一个程序员绝对没有料到这么简单的逻辑在之后会变成这么复杂的模块,甚至在增添第一第二条else时,也只是很随意的加上。

  ⒗所以我觉得,这个锅绝对是是甲方的,让他娘的随便改需求。

  ⒘这么一想心里就好受多了,编程嘛,最重要的是要看的开。

  ⒙于是我又增加了两条else,测试,提交,下班。

  ⒚有时候真的不是我们不想写好代码,是不能写好代码。写着写着需求砍了、需求变了,什么设计模式都不顶用,最终还是怎样快怎样方便怎样来,因为根本没人知道这段代码还能不能活的过下一段需求变动。

  ⒛有的人肯定要说怎么不订合同。合同肯定是有的,但是明明白纸黑字写的合同,该改还是得改,毕竟你要是不同意甲方那些“微小的变动”,以后还做不做了?!金主真能去得罪?

  还是要学会得过且过,跟什么过不去也不能跟自己过不去,糟糕的代码忍一忍就完了:代码能跑、头发不少,对我们这些打工的人而言比什么都重要。

  现实工作绝不是课本中的理想状态,会有无数的突发情况在等着你。你定义了半天观察者、备忘录,第二天这部分需求被砍了;写了半天接口,抽象类,忽然下午告诉你要加个十万八千里打不着边的啥东西,于是又开始加适配器,等你加完了告诉你又砍了。甚至有次半夜被喊起来改代码,等改完了发现需求被撤回了,气的我直接请了两天假调整心情。

  设计模式和大的框架绝对是一个项目中非常重要的东西,但不是绝对重要的;一个好的PM团队,在某种意义上,才真正决定了这个项目的代码质量。

  请用秒钟的时间查看下面的代码是否存在bug。

  OK,熟练的程序猿应该已经发现Bug所在了,在第行和第行下面我没有添加关键字break;这就导致这段代码的行为逻辑与我的设计初衷不符了。缺点一.语法正确,逻辑错误

  这就是第一个理由为什么程序猿很少使用switch来做条件判断,对于新手来说忘记写break实在是再普通不过了,就算是老猿忘记写也是时有发生的事情,而这个语法错误在诸多的语法检查器上没有办法检查出来的,因为从语法角度来说是正确的!可是代码的处理逻辑却是错误的!用if来重写这段代码的话,就不会发生这种错误。

  上面的代码为了保证正确我添加了else做一个逻辑上的保证,其实如果不写else,这段代码也不会发生逻辑错误,而且一旦我忘记写花括号的时候,语法编译器是会提示我添加的,甚至可以使用eslint这种的工具强制我使用花括号,这样就不会犯语法错误了,一旦出现bug,那么肯定是我逻辑上的问题了。缺点二.死板的语法

  switch尽管对于break很宽容,但是对判断条件很严苛,case后面只能跟常量,如果你用C编写的话,甚至只能用int类型作为判断条件。对于我们这么潇洒自如的程序猿来说,这种限制实在是太麻烦了,用if的话,别说是常量了,我用函数都可以,真正做到方便快捷。缺点三.需要子函数来处理分支

  这个缺点跟缺点一有关,为了防止漏写break,因此建议把分支处理方法独立成一个子函数来处理,这样在阅读代码的时候就会减少忘记写break带来的bug,那么用if来写的话,我想怎么写就怎么写,非常随意自由,但是这也导致了代码的可读性大大降低。

  既然switch有这么严重的缺点,那怎么在所有语言中依然会存在呢?那就说下switch的优点吧,它的优点也刚好是它的缺点。

  在很久很久以前,那时候的电脑性能还不如一台小霸学习机的时候,聪明的计算机科学家为了提高计算机的处理速度,将一些逻辑分支处理方法简化了一下,把一些需要做逻辑判断的操作给固定死,然后只要查表一样一个一个对一下就能做出相应的反应了。

  比如说a=的判断,switch和if在cpu上面的处理方式是不一样的,switch是在编译阶段将子函数的地址和判断条件绑定了,只要直接将a的直接映射到子函数地址去执行就可以了,但是if处理起来就不一样了。

  它首先要把a的值放到CPU的寄存器中,然后要把比较的值放到CPU的另一个寄存器中,然后做减法,然后根据计算结果跳转到子函数去执行,这样一来就要多出步的操作了,如果逻辑判断多的话,那么将会比switch多处许多倍的操作,尽管寄存器操作的速度很快,但是对于当时的学习机来说,这点速度根本不够用啊。

  那还有一个问题,为什么要使用break来做一个判断结束呢?这不是很容易造成语法错误了?那就要说到子函数的问题上了。

  在早起的电脑代码中是没有子函数的概念的,那时候都是用goto随意跳转的,你想去第行代码,很简单goto就可以了。这种编程思维在C的早期阶段还是一直受到影响的,因此早期的C也没有子函数,都是一堆逻辑处理混乱在一起,goto满天飞,所以那时候你没有一个最强大脑是写不了程序的。那为了告诉程序我这里条件判断处理结束,就添加了break作为终止符号。后来慢慢的有了子程序,有了更好的编程规范,才一步一步的将写代码沦落到体力劳动。

  后来发展的新语言为了标榜自己的血统,多少都要参考下C,然后就把switch这种诡异的语法也继承下来了。但是也不是所有的语言都照搬,比如Google发明的新语言golang和kotlin就又把switch包装了一下,去掉了令人误会的语法,又让switch变得灵活起来了,对了,在代码重构的时候,还是用switch把,这样看起来的确代码更简洁哦!

  switch只能用于简单判断,不支持表达式。

  没有ifelse使用方便。

  不是尽量别用,而是不合适没法用,合适得时候该用还是用。

  比如说,变量i要求大于,小于,一条if(i》&&i

  Kotlin进阶系列-函数类型及函数字面值

  在Kotlin中,函数是一等公民(firstclass,这意味着函数可以被存储在变量或者数据结构中,它是有类型的。Kotlin使用函数类型来描述一个函数的具体类型。一个完整语法的函数类型如下:

  接收者类型在参数前,和参数所在的小括号用点连接。关于带接收者的函数类型在之后会详细讲解。

  既然函数有类型,那函数类型变量的值是什么呢?这就涉及到函数类型的实例化。函数类型的实例化包括以下几种常用方式。

  a.lambda表达式:

  a.顶级,本地,成员或者扩展函数。例如:String::toInt。

  b.顶级,成员,或者扩展属性:List::size。

  c.构造函数:::Regex。

  函数类型的值可以通过invoke操作符调用,以下是示例。

  lambda表达式的全语法形式如下:

  Kotlin有一个约定:如果函数的最后一个参数是函数,那么作为相应参数传入的lambda表达式可以放在圆括号之外。示例如下:

  以lambda表达式作为参数的高阶函数如下:

  其调用示例可以简写为:

  如果lambda表达式是唯一的参数,那其圆括号可以省略,示例如下:

  自Kotlin.起,如果lambda表达式的参数未使用,那么可以用下划线取代其名称:

  lambda表达式不能显示的指定返回值的类型。如果需要显示指定返回值的类型,则需要使用匿名函数。匿名函数和普通函数非常类似,除了其函数名被省略。其示例如下:

  anonymousTest中对匿名函数的调用是完整语法形态,由于参数类型和返回值类型可以推断,因此,其可以简写为

  请注意,匿名函数参数总是在括号内传递。允许将函数留在圆括号外的简写语法仅适用于lambda表达式。

  为什么Kotlin调用java时可以使用Lambda

  Kotlin中的Lambda表达式

  如果你已经开始使用Koltin,或者对它有过一些了解的话,那么一定对这种写法并不陌生了:

  //代码一:Kotlin代码view.setOnClickListener{println(“click“)}

  它跟下面这段Java代码是等价的:

  //代码二:java代码view.setOnClickListener(newView.OnClickListener(){??OverridepublicvoidonClick(Viewv){System.out.println(“click“);}});

  和Java一样,Kotlin是支持Lambda表达式的,如代码一所示,就是Lambda的一个具体应用。

  可见,使用lambda减少了很多冗余,使代码写起来更简洁优雅,读起来也更顺畅自然了。

  但是,你有没有想过,为什么Kotlin可以这样写,这里为什么可以使用lambda?

  在Kotlin中,一个Lambda就是一个匿名函数。

  代码一其实是对下面代码三的简写:

  //代码三:Kotlin代码view.setOnClickListener({v-》println(“click“)})

  之所以简写成代码一的样子,是基于这两点特性:

  OK,从代码三的结构中,能够更清晰的看出,这里的view.setOnClickListener函数是接收了一个lambda作为参数。而在Kotlin中,什么样的函数才能把lambda(也即另一个函数作为参数呢?——对,就是高阶函数。

  高阶函数是将函数用作参数或返回值的函数。

  这是Kotlin和Java的区别之一,java中并没有高阶函数的支持(java是有高阶函数的。当我们在java中需要用到类似的概念时,通常的做法是传递一个匿名类作为参数,然后实现其中的某些抽象方法——就比如上面的代码二。

  事实上,如果在AndroidStudio中,从Kotlin的代码查看view.setOnClickListener函数的定义,就会发现,看到的函数签名就是一个高阶函数的定义:

  如上图,所看到函数签名是:

  publicfinalfunsetOnClickListener(l:((v:View!)-》Unit)!):Unit

  当然,因为方法是在Java中定义的,所以它也列出了Java的声明,是这样:

  publicvoidsetOnClickListener(OnClickListenerl)

  我们知道,Kotlin跟Java的很多类型都有差异,所以它们在互相调用的时,会有一个按照对应关系的转换。

  对于上面的对setOnClickListener方法的转换,别的地方都好理解,比较难懂的是,为什么会把参数从?OnClickListener?类型转换成了?(View)-》Unit。

  (View)-》Unit?是一个函数类型,它表示这样一个函数:接收个View类型的参数,返回Unit。

  正是这个对参数类型的转换,使得setOnClickListener方法在Kotlin中变成了一个高阶函数,这样正是它之所以能够使用lambda作为参数的原因。

  而这种转换,就是我们题目中所说到这篇文章的主角——?SAM转换?(SingleAbstractMethodConversions)。

  好吧,说了这么多,终于到正题了。

  SAM转换,即SingleAbstractMethodConversions,就是对于只有单个非默认抽象方法接口的转换——对于符合这个条件的接口(称之为?SAMType?,在Kotlin中可以直接用Lambda来表示——当然前提是Lambda的所表示函数类型能够跟接口的中方法相匹配。

  而?OnClickListener?在java中的定义是这样的:

  ——恰好它就是一个符合条件的?SAMType,onClick函数的类型即是?(View)-》Unit。所以,在Kotlin中,能够用lambda表达式?{println(“click“)}?来代替?OnClickListener?作为setOnClickListener函数的参数。

  SAM转换的歧义消除

  SAM转换的存在,使得我们在Kotlin中调用java的时候能够更得心应手了,它在大部分的时间都能工作的很好。

  当然,也偶尔会有例外,比如,考虑下面的这段代码:

  ——TestSAM有两个重载的setSam方法,——并且它们的参数(SamType、SamType)都是?SAMType?的接口。——并且SamType跟SamType的唯一抽象方法的函数类型都是?(Int)-》Unit?。

  这种情况比较吊轨,但是还有有可能会出现的。这时候,如果在Kotlin中直接使用代码一类似的方式,就会报错了:

  会提示这里歧义,编译器不知道这个Lambda代表是SamType跟SamType中的哪一个接口。

  解决的办法就是手动标明Lambda需要代替的接口类型,有两种方式可以来标明:

  当然,也还有一种方法是不再使用SAM转换的机制,而是直接使用一个SamType的实例作为参数:

  这种方法当然也是可以的,只是跟lambda相比起来,就显得不那么优雅了(优雅很重要!!!。

  SAM转换的限制主要有两点:

  即只适用与Kotlin中对java的调用,而不支持对Kotlin的调用

  官方的解释是Kotlin本身已经有了函数类型和高阶函数等支持,所以不需要了再去转换了。

  如果你想使用类似的需要用lambda做参数的操作,应该自己去定义需要指定函数类型的高阶函数。

  只支持接口,不支持抽象类。

  这个官方没有多做解释。

  我想大概是为了避免混乱吧,毕竟如果支持抽象类的话,需要做强转的地方就太多了。而且抽象类本身是允许有很多逻辑代码在内部的,直接简写成一个Lambda的话,如果出了问题去定位错误的难度也加大了很多。

  OK,讲完了。总结起来就是?SAM转换就是kotlin在调用java代码时能使用Lambda的原因。了解了其原理,能够让我们在写代码更自如,在偶尔出问题的时候也能更好更快地解决。

  四,Kotlin高阶函数详解

  什么是高阶函数?高阶函数定义:参数有函数类型或者返回值是函数类型的函数。在Kotlin中增加了一个函数类型的概念,如果我们将这种函数添加到一个函数的参数声明或返回值声明当中,那么这就是一个高阶函数了。函数类型语法基本规则:函数类型定义:添加到某个函数的参数声明,那么该函数称之为高阶函数了例子参数有函数类型高阶函数有三种用法定义一个高阶函数双冒号::method形式的用法匿名函数形式的用法Lambda表达式形式的用法通常方式使用高阶函数map例结果:列,使用,莲姐字符串操作例:例:结果例例高阶函数就是多阶映射。高阶函数用另一个函数作为其输入参数,也可以返回一个函数作为输出。

  Kotlin带接收者的lambda表达式

  在学习kotlin协程原理的时候发现了一个比较有意思的东西:

  这个block参数的类型是:

  suspend是一个关键字,在协程里面用于声明挂起函数,我们先忽略。看后面的CoroutineScope.()-》Unit看起来像是个函数类型,但是比起一般的函数类型又多了前面的”CoroutineScope.“前缀。

  这玩意学名叫做带有接收者的函数类型,通过文档我们可以知道它和扩展函数类似,允许在函数体内部访问接收者对象的成员。也就是说在lambda内部,传给调用的接收者对象成为隐式的this,我们可以用this去访问它的成员变量。这个时候invoke的第一个参数就是接收者也就是this的值:

  然后this也可以省略:

  通过kotlin的语法糖我们可以将invoke省略,将with方法写成下面的形式:

  由于block的接收者是Person类型的,通过“Person.()-》Unit“这个类型声明,其实我们可以将它看成Person的拓展函数,通过person这个传入的对象去调用,也就是说我们可以将with方法再改成这样的形式:

  对kotlin熟悉的同学可能想到了,如果将特定的Person类型改成泛型,然后再将block的返回值返回,就是我们常用的with函数的实现原理:

  如果with方法是Person的成员方法,那么输入的person接收者就是this,可以不用特地在方法参数指定。也就是说可以把它去掉写成下面的形式:

  这个时候就更像给Person类创建了一个拓展方法。接收者是this,这个this就是我们传入的person变量。然后this同样可以省略,写成下面的形式:

  如果我们使用泛型去替代这个特定的Person类,然后将this再返回,就是apply方法的实现原理了:

  很多的kotlinDSL就是用上面的带有接收者的lambda函数去实现的,例如anko。我们可以先给ViewGroup声明一个拓展方法textView用于创建TextView添加成子view,然后TextView作为接收者去调用lambda方法block:

  然后再声明一个Activity的拓展方法verticalLinearLayout用于创建垂直布局的LinearLayout,然后将这个创建的LinearLayout作为接收者去调用lambda方法block:

  所以就有了下面这样的写法,创建一个垂直布局的LinearLayout里面包含两个TextView:

  我们对这个dsl进行详细的解析,第一步它调用了Activity的拓展方法verticalLinearLayout,它的接收者是Activity,内部创建了一个LinearLayout返回。并且用它做接收者调用lambda函数,在lambda函数内部调用的textView方法是ViewGroup的拓展函数,它内部创建了一个TextView加入到LinearLayout的子view。并用这个TextView做接收者调再用lambda函数,所以可以直接设置TextView的setText方法和setBackgroundColor方法。

  除了上面kotlin内置的with、apply方法和anko的实现之外,官方文档也提供了一个比较典型的例子:

  html方法接收一个带HTML类型接收者的lambda函数,它在内部自己创建一个HTML的实例去调用这个lambda函数,于是可以在这个lambda函数里面调用HTML的body方法。

  通过上面的几个例子,我们已经了解了带接收者的lambda函数的使用方法,我们可以通过这些典型的用法去设计我们自己的DSL使得我们设计的框架更加易用。

  kotlin中的匿名函数&Lambda

  匿名函数定义:匿名函数是指的没有函数名字的函数,例子如下:funmain(){vallen=“kiiiing“.count();println(len)vallen=“kiiiing“.count{????it==’i’??}??println(len)}其中的“kiiiing“.count{}就是匿名函数,相当于一个表达式,有返回值,这个匿名函数内部是类型为char,变量名为it的字符,相当于把kiiing字符串分解.匿名函数的类型和隐式返回例子如下:funmain(){//函数输入输出的声明??valmethodAction:()-》String??//对上面函数的实现,这里是匿名函数,匿名函数没有返回值,即不需要写return,最后一行就是返回的内容??methodAction={?????“hello“??}??println(methodAction())}.匿名函数参数的学习对比上面拆解的方式定义一个匿名无参函数,下面是一个整合形式的有参匿名函数的定义:funmain(){??valmethodAction:(Int,Int,Int)-》String={n,n,n-》????“valueis${n},${n},${n}“??}??println(methodAction(,,))}.匿名函数中it关键字的学习funmain(){//如果定义了一个参数的匿名函数,默认it参数名字??valmethodAction:(String)-》String={it}}.匿名函数的类型推断funmain(){//匿名函数的返回值推断??valmethdFunction={v:Double,v:Float,v:Int-》?????““??}}.lambda的学习funmain(){//匿名函数==lambda表达式??valaddNumResult={number:Int,number:Int-》????“两数相加的和:${number+number}“??}??println(addNumResult(,))//匿名函数返回Any类型,lambda表达式的参数Int,lambda表达式结果Any类型??valweekResumtMethod={number:Int-》????when(number){-》“星期一“??????-》“星期二“??????-》“星期三“??????-》“星期四“??????-》“星期五“??????else-》-????}}??println(weekResumtMethod())}.匿名函数中参数是函数的函数funmain(){loginApi(“king“,““,responseResult={reason:String,code:Int-》????println(“登陆情况${reason}“)})}constvalUSER_NAME_SAVE_DB=“king“constvalUSER_NAME_SAVE_PWD=““funloginApi(username:String,userpassword:String,responseResult:(String,Int)-》Unit){if(username==null||userpassword==null){TODO(“用户名密码为空“)//出现问题,终止程序??}if(username.length》&&userpassword.length》){if(webServiceLoginApi(username,userpassword)){//登陆成功???????responseResult(“loginsuess“,);}else{//登陆失败???????responseResult(“loginfailed“,);}}else{TODO(“用户名密码不合格“)}}privatefunwebServiceLoginApi(name:String,passowrd:String):Boolean{returnif(name==USER_NAME_SAVE_DB&&passowrd==USER_NAME_SAVE_PWD){true??}else{false??}}.匿名函数参数是函数的函数的简化写法funmain(){//第一种写法??loginApi(“king“,““,{reason:String,code:Int-》????println(“登陆情况${reason}“)})//第二种写法??loginApi(“king“,““,responseResult={reason:String,code:Int-》????println(“登陆情况${reason}“)})//第三种方式??loginApi(“king“,““){reason:String,code:Int-》????println(“登陆情况${reason}“)}}.匿名函数的内联学习--如果一个函数的参数没有lambda,就不需要声明成内联--如果一个函数的参数有lambda表达式()如果一个函数不使用内联,在使用前会生成多个对象来完成lambda的调用()如果一个函数使用内联,相当于c++中的宏定义,宏替换结论:如果函数参数有lambda,尽量使用incline关键帧,内部会做优化,减少函数,对象开辟的损耗.函数引用函数引用是指把普通函数变成函数类型的对象::函数名可以转换成对象,一个函数lambda参数funmain(){loginApi(“king“,““,::excuteResponseResult)}funexcuteResponseResult(reason:String,code:Int){println(“suess“)}constvalUSER_NAME_SAVE_DB=“king“constvalUSER_NAME_SAVE_PWD=““funloginApi(username:String,userpassword:String,responseResult:(String,Int)-》Unit){if(username==null||userpassword==null){TODO(“用户名密码为空“)//出现问题,终止程序??}if(username.length》&&userpassword.length》){responseResult(“loginsuess“,);}else{TODO(“用户名密码不合格“)}}.函数类型作为返回类型funmain(){show(““)}funshow(value:String):(String,Int)-》String{return{name:String,age:Int-》????““??}}

  Kotlin基础知识六:标准函数(StandardFunctions

  apply函数可以理解为是一种配置函数。它允许你在receiver上调用一系列的函数、而不需要在每个函数前都加上变量名。当lambda执行完成后,apply()函数返回调用者的实例。举例:let扩展函数的实际上是一个作用域函数,当你需要去定义一个变量在一个特定的作用域范围内,let函数的是一个不错的选择;let函数另一个作用就是可以避免写一些判断null的操作。举例:避免判空的写法:apply接收的函数类型为()-》Unit,即无参、无返回值,匿名函数执行结束后,会返回当前的receiver;然而let接收的函数类型为(T)→R,其中T为调用者类型,R为匿名函数中返回的特定类型,或lambda表达式最后一行返回的类型。run函数与apply类似,不同点是run的返回值是lambda的结果,然而apply的返回值是调用者,即receiver。run还可以用来在receiver上执行一个functionreference。使用run函数实现链式调用(chainedcalls比嵌套的函数调用更容易阅读和跟踪。例如,判断名字是否大于个字符、并根据结果生成格式化消息、然后打印出来。如果使用嵌套调用时:如果使用run函数链式调用:run函数也可以脱离receiver而使用:目的:用于对同一个对象执行多次操作而不需要反复把对象的名称写出来。performmultipleoperationsonthesameobjectwithoutrepeatingitsname.考虑以下例子:在result实例上调用不同的方法时,每次都需要重复result这个名字。with函数有两个参数,第一个参数为任意类型的对象实例,第二个参数是一个lambda表达式。with函数会把第一个参数转换为lambda表达式的接受者。可以通过显式的this指针调用接受者的方法。使用with函数重写:进一步简化的写法:also与let非常相似,都会把receiver作为参数传递给lambda,不同点是also会返回receiver,而let返回的是lambda的结果。因为also函数会返回receiver本身,所以可以在同一receiver上执行also的链式调用。举例:takeIf会执行一个断言(predicate函数,如果断言函数返回true,takeIf返回receiver本身;如果返回false,则takeIf返回null。如果不使用takeIf的写法:可见,takeIf不需要临时变量file,也不需要专门处理返回null的情景。如果断言函数返回false时,返回this值;否则,返回null。举例,当一个文件不是隐藏文件时,读取出文件内容:

您可能感兴趣的文章:

相关文章