kotlin
2017-07-25 10:56
183 查看
kotlin学习
参考网址:http://www.jianshu.com/p/6063dee97eca
http://blog.csdn.net/qq562029186/article/details/72519360
一、常量、变量、特殊符号的使用
1、常量的定义 val
2、变量的定义 var
3、特殊符号的使用
1)?的含义:在kotlin中单独使用?表示可为空;
如:kotlin代码书写格式:
var result = str?.length
java代码书写格式:
if(str == null) result = null; // 这里result为一个引用类型 else result = str.length; // 这里result为Int
2)!!的含义:在kotlin中表示一定不能为空;
如:var str : String? = null var result : Int = str!!.length
3)?:的含义:在kotlin中表示三元操作符(即三目运算符)
如:var str : String? = null var result = str?.length ?: -1 //等价于 var result : Int = if(str != null) str.length else -1
二、定义类
1、属性修饰符
annotation //注解类
abstract //抽象类
final //类不可继承,默认属性
enum //枚举类
open //类可继承,类默认是final的
访问权限修饰符
private //仅在同一个文件中可见
protected //同一个文件中或子类可见
public //所有调用的地方都可见
internal //同一个模块中可见
2、构造器的定义
注:kotlin中的类定义同时也是构造函数,这个时候是不能进行操作的,所以kotlin增加了一个新的关键字init用来处理类的初始化问题,init模块中的内容可以直接使用构造函数的参数。class Person(name:String,age:int){ init{ //do some thiing } }
翻译成java为:
final public class Person{ public Person(String name,int age){ init(); } private void init(){ //do some thing } }
3、java中加入final为不可继承,而kotlin中定义类默认前面带有修饰符final,所以,如果想继承该类,在最前面加上open或者abstract即可。即:
open class Person(name : String, age : int) { init{ // do some thing } }
4、如果init中没有操作,则可以省略
class Person(name : String, age : int)
5、如果连参数也没有,甚至可以这么写
class Person
6、但是当构造参数中的参数、类型变化时可能需要不只是一个构造函数,需要多组构造函数来处理不同view上的数据时,使用constructor加上参数,后面用this加上主构造函数的参数。
次级构造函数
class Person(name:String){ var a = 1 init{ log("This is --> primary constructor,a = $a,name = $name") } constructor(name:String,age:Int): this(name){ log("This is --> secondry constructor,a = ${++a}, age = $age") } } // 翻译成java final class Person{ int a = 1; public Person(String name){ log("This is --> primary constructor, a=$a, name=$name") } public Person(String name, int age){ this(name); log("This is --> secondry constructor, a=${++a}, age=$age") }
}
特别注意:
1)同理,如果参数全是固定值,则kotlin会默认创建一个无参数的构造函数;2)固定值的参数在调用该构造函数时可以不用传。
3)如果P1(name,age)双参,P2(name,age,1)三参,那么kotlin中默认会调用双参的P1来执行,不会去执行P2;
三、定义函数方法
1、求和
方式一:
带有两个 Int 参数、返回 Int 的函数fun sum(a:Int , b :Int):Int{ return a+b; } fun main(args: Array<String>){ print("sum of 3 and 5 is") print(sum(3,5)) }
result:sum of 3 and 5 is 8
方式二:
将表达式作为函数体、返回值类型自动推断的函数fun sum(a:Int,b:Int) = a + b fun main(){ println("sum of 19 and 23 is ${sum(19,23)}") }
result:sum of 19 and 23 is 42
方式三:
函数返回无意义的值fun printSum(a:Int,b:Int):Unit{ println("sum of $a and $b is ${a+b}") } fun main(args:Array<String>){ printSum(-1,8) }
result:sum of -1 and 8 is 7
方式四:
Unit 返回类型可以省略fun printSum(a:Int,b:Int){ println("sum of $a and $b is ${a+b}") } fun main(args:Array<String>){ printSum(-1,8) }
2、数组
使用泛型Array代替数组
Java: public static void main(String[] args){ // do some thing } Kotlin: fun main(args : Array<String>){ // do some thing }
3、条件语句
fun max(a:Int,b:Int){ if(a > b) return a else return b } //或者简写成: fun max(a:Int,b:Int) = if( a > b) a else b
4、循环
1)for循环
使用in关键字fun main(args:Array<String&g 4000 t;){ for(arg in args) print(arg) for(i in args.indices) print(arg[i]) for((index,value) in args.withIndex()){ println("index : $index,value : $value") } }
2)while循环
和JAVA使用基本一致fun main(args : Array<String>){ var i = 0 while(i < args.size){ print(args[i++]) } var j = 0; do{ print(args[j]) }while(++j<args.size) }
3)when表达式
和switch用法类似无返回值时用法:
var x = 3 when (x){ 1 -> print(1) 2 -> print(2) else -> print(5) }
有返回值
var x = 3 var result = when(x){ 1 -> 1 2 -> 2 else -> 5 }
处理相同分支的简写
when(x){ 0,1 -> print("x == 0 or x == 1") else -> print("otherwise") }
任意表达式做分支的条件
is 表示检查一个值
in 表示范围区间
如果有多个条件同时满足,则调用第一个满足条件的分支
when(x){ parseInt(s) -> print("s encode x") else -> print("s does not encode x") } fun parseInt(str : String) = str.toInt() when(x){ in 1..10 -> print("x is in the range") in validNumbers -> print("x is valid") !in 10..20 -> print("x is outside the range") else -> print("none of the above") } //不去校验任何参数 when{ a is Int -> log("a is Int") // a is Int else -> log("unknow type") }
4)if表达式
var a = 3 var b = 5 var max : Int if(a > b) max = a else max = b log("普通 max : $max") //普通 max : 5
也可简写成:
max = if(a > b) a else b log("表达式 max : $max") //表达式 max : 5
5)返回和跳转
JAVA中使用:return、break、continueKotlin中新增跳出循环操作:使用标识符@定义label,使用在多层循环的内层向外层跳转。
break和label结合跳转到指定循环层,即使用label1@在跳出循环层的循环操作前面,然后执行完什么操作就跳出时加入代码 break@label1
var list = arrayof(1,2,3) var child = arrayof("a","b","c") var result = "" label1@ for(num in list){ // --> 第一层循环 result +="($num)" for(word in child){ // --> 第二层循环 if(word.equals("b")){ break@label1 // --> break + label } result += word } } log(result) //输出 (1)a
continue和label结合跳转到指定循环层,继续下一次循环。当条件满足时跳出内层循环继续执行外层循环。
label2@ for(num in list){ // --> 第一层循环 result += "($num)" for(word in child){ // --> 第二层循环 if(word.equals("b")){ continue@label2 // --> continue + label } result +=word } }
5、继承
在java中使用的是extend,kotlin中继承变成 :
继承五步曲:1)使用:来做继承
2)父类使用open声明类,不然默认final,无法继承
3)父类构造函数中有参数则在继承时带上
4)子类中使用constructor创建的次级构造函数初始化时使用super关键字
5)父类中的方法如果需要重写,则需要在该方法前加上open关键字,同样,子类如果需要修改或重载该方法也需要在引用处加上override关键字。
1、多级构造函数的继承
父类: open class ParentClass(name:String){ var a = 1 init{ log("This is --> primary constructor, a=$a, name=$name") } } 子类: //无次级构造函数的写法 class Child(name:String,age:Int) : ParentClass(name){ } //有次级构造函数的写法: class Child2 : ParentClass { constructor(name :String) :super(name){ log("Child2 age : $name") } constructor(name:String,age :Int) :super(name){ } }
2、方法重载
//父类 open class ParentClass(name: String) { open fun publicMethod(){ log("I am public") } } //子类 class Child(name: String, age : Int) : ParentClass(name){ override fun publicMethod() { super.publicMethod() } }
3、同名方法
当这个父类中有2个方法同名,参数相同时,kotlin中使用尖括号来进行标记父类,以示区分。
//父类 open class ParentClass(name :String){ open fun publicMethod(){ log("I am public from ParentClass") } } interface ParentInterface(name :String){ fun publicMethod(){ log("I am public from ParentInterface") } } //子类 class Child(name :String,age :Int) :ParentClass(name),ParentInterface{ override fun publicMethod(){ super<ParentClass>.publicMethod() super<ParentInterface>.publicMethod() } }
4、抽象
抽象主要是将不同的实现交给不同的子类去完成
//父类 abstract class ParentClass(name: String) { abstract fun abstractMethod() } //子类 class Child(name: String, age : Int) : ParentClass(name){ override fun abstractMethod() { //To implemented it } }
5、属性声明、get、set的使用
1)访问权限
var name :String = "" private set //但是不能使用private get,因为get的访问权限默认是和属性一致的
2)自定义getter和setter
var有set和get,val只有get
// 自定义get var size: Int = 2 get() = if (field > 10) 15 else 0 // 调用 var pf = PropertiesFields() pf.size = 5 Log.d("text", "size : ${pf.size}") pf.size = 20 Log.d("text", "size : ${pf.size}") // 输出 size : 0 size : 15 // 自定义set var size: Int = 2 set(value) { field = if (value > 10) 15 else 0 } // 调用和输出同上
3)后端变量
在kotlin的getter和setter是不允许本身的局部变量的,因为属性的调用也是对get的调用,因此会产生递归,造成内存溢出。
kotlin为此提供了一种我们要说的后端变量,也就是field。编译器会检查函数体,如果使用到了它,就会生成一个后端变量,否则就不会生成。我们在使用的时候,用field代替属性本身进行操作。
4)延迟初始化属性(lateinit)
延迟属性类似于JAVA中的懒汉式单例模式
//延迟初始化声明 lateinit var late : String fun initLate(){ late = "I am late" } //先调用方法,再调用属性 var pf = PropertiesFields() pf.initLate() Log.d("text",pf.late) //输出 I am late
注:一定要确保属性是被初始化过的,这样再调用方法,再调用属性,否则会出现属性的NULL异常现象。
6、 接口interface
1)定义接口、方法和属性接口属性默认是abstract,在接口中不能初始化,必须在实现类中进行初始化,并且在初始化时要加override修饰
在具体类中可以不用覆写接口中的实现方法,直接调用
interface Wing{ fun fly(){ Log.d("text", "Wing -> fly") // 这里实现了接口的方法 } } //JAVA中引入接口中的方法使用implement关键字,而kotlin中使用冒号: class InterfaceLesson : Wing{ override fun fly(){ super.fly() // 在具体类中可以不用覆写接口中的实现方法,直接调用 } } // 输出 Wing -> fly
2)继承和多继承重载
接口只能继承接口
a、子类中调用父类方法需要使用super方法调用接口来实现
b、接口没有实现方法,子类必须实现方法且不能调用super
c、多个接口中都有相同的方法,无论接口中是否实现,子类都必须实现该方法。如果二个接口中都没有实现,则子类不能使用super;如果有一个接口实现了,则子类可以使用super且自动调用实现的方法;如果二个接口都实现了该方法,则子类在调用super时需要使用尖括号对调用的父方法进行声明。
例1:
interface Foot{ fun run() } interface Car{ fun run() } class InterfaceLesson : Foot, Car{ override fun run() { } }
例2:
interface Foot{ fun run() } interface Car{ fun run() { Log.d("text", "Car -> run1") } } class InterfaceLesson : Foot, Car{ override fun run() { super.run() } } // 输出 Car -> run1
例3:
interface Foot{ fun run() { Log.d("text", "Foot -> run") } } interface Car{ fun run() { Log.d("text", "Car -> run1") } } class InterfaceLesson : Foot, Car{ override fun run() { super<Foot>.run() } } // 输出 Foot -> run
7、 扩展Extension
1)扩展方法java中调用toast需要写成封装的工具类或者BaseActivity中实现toast方法,而kotlin中则不需要这样做,只要在需要的Activity或者Fragment中创建fun方法,实现context的扩展,增加toast方法即可。
// 对Context的扩展,增加了toast方法。为了更好的看到效果,我还加了一段log日志 fun Context.toast(msg : String){ Toast.makeText(this,msg,Toast.LENGTH_SHORT).show() Log.d("text","Toast msg : $msg") } // Activity类,由于所有Activity都是Context的子类,所以可以直接使用扩展的toast方法 class MainActivity : AppcompatActivity(){ override fun onCreate(savedInstanceState : Bundle?){ ...... toast("Hello,Extension") } } //输出 Toast msg : Hello,Extension
2)扩展属性
扩展属性也有set和get方法,并且必须要实现这2个方法,不然编译会出错。
//1、 扩展了一个属性paddingH,并给属性增加set和get方法 var View.paddingH : Int get() = (paddingLeft + paddingRight) / 2 set(value) { setPadding(value,paddingTop,value,paddingBottom) } //2、设置值 activity中通过textview调用 text.paddingH = 100
3)静态扩展
kotlin中的静态用关键字companion表示,它不是修饰属性或方法,而是定义一个方法块,在方法块中的所有方法和属性都是静态的,静态部分的访问和java一致,直接使用类名+静态属性/方法名就可以
//定义静态部分 class Extension { companion object part{ var name = "Extension" } } //通过类名+属性名直接调用 toast("hello,${Extension.name}") //输出 Toast msg : hello,Extension
注:companion object一起是修饰关键字,part是方法块的名称。其中,方法块名称part可以省略,如果省略的话,默认缺省名为Companion
8、数据类
保持数据或状态,在JAVA中用bean或entity或自定义model或sp保存持久等等,而kotlin中用data关键字来处理。data class PersonData(var name : String, var age : Int)
使用data修饰的类叫做数据类,编译器自动从主构造函数定义的全部特性中得到以下成员:
equal()/hashCode() toString 格式是 "PersonData(name = PersonData,age = 20)" componentN()方法对应按声明顺序出现的所有属性 copy()方法
<
ffbb
h6 id="1tostring输出">1)toString输出
// 定义数据类和普通类 data class PersonData(var name : String , var age : Int) class PersonNormal(var name : String,val age : Int) // 分别初始化并进行toString输出 fun test(){ var personD = PersonData("personData",20) var personN = PersonNormal("personNormal",20) Log.d("test",personD.toString()) Log.d("test",personN.toString()) } //输出 PersonData(name = PersonData,age = 20) 包名.类名PersonNormal@地址(26b13e2)
2)copy
修改类中的内容(修改上面的PersonData中的内容)
var personC = personD.copy("Person Copy") //默认第一个参数 var personC = personD.copy(age = 100) //可指定需要修改的参数 Log.d("test",personC.toString()) //输出 PersonData(name = person Copy,age = 100)
3)变量的映射
编译器自动生成的componentN()方法
var personD = PersonData("PersonData",20) var(name,age) = personD //多声明可翻译成如下 //var name = f1.component1() //var age = f1.component2() Log.d("test", "name = $name, age = $age") //输出 name = PersonData, age = 20
4)数据的序列化
JAVA中通过Parcelable插件自动进行序列化,而kotlin中暂时只能自己实现。
data class PersonData(var name : String, var age : Int, val sex : String) : Parcelable{ override fun writeToParcel(p0: Parcel?, p1: Int) { p0?.writeString(this.name) p0?.writeInt(this.age) p0?.writeString(this.sex) } override fun describeContents(): Int { return 0 } constructor(source: Parcel) : this(source.readString(), source.readInt(), source.readString()) companion object { @JvmField val CREATOR: Parcelable.Creator<PersonData> = object : Parcelable.Creator<PersonData> { override fun createFromParcel(source: Parcel): PersonData { return PersonData(source) } override fun newArray(size: Int): Array<PersonData?> { return arrayOfNulls(size) } } } }
##还有待追新研究下…
9、泛型
1)JAVA中泛型的使用from是生产者,to是消费者。
extends关键字限定类型上限,super关键字限定类型下限。
//定义类 class Data<T>{} //定义接口 interface Data<T>{} //定义方法 public <T> void data(T t){} //使用通配符 //用?表示任何类型,结合extends和super关键字可以限定类型的上限和下限 class Data<T>{} // extends关键字限定类型上限,表示类型必须是String或String的子类 public void dataUpper(Data<? extends String> d){} // super关键字限定类型下限,表示类型必须是String或String的父类 public void dataLower(Data<? super String> d){} //使用通配符解决数据调用问题 fun copy(from: Array<A>, to: Array<A>) { for (i in from.indices) to[i] = from[i] }
2)kotlin中泛型的使用
kotlin中添加了协变注解修饰符:in和out(in对应to,out对应from)
in T:来确保Source的成员函数只能消费T类型,而不能返回T类型,我们也称in修饰的参数为“消费者”
out R:来确保Source的成员函数只能返回R类型,而不能消费R类型,我们也称out修饰的参数为“生产者”
out类似于java中的extends,用来界定类型上限,in类似于java中的super,用来界定类型下限。
//定义类 class Data<T>(var t : T) //定义接口 interface Data<T> //定义函数 fun <T> logic(t : T){} //使用通配符解决数据调用问题 fun copy(from: Array<out A>, to: Array<in A>) { for (i in from.indices) to[i] = from[i] }
另附:
kotlin中新增—–> 星号投射(还需挖掘)
interface Function
10、嵌套类、内部类
1)嵌套类class Outter{ class Nested{ fun execute(){ Log.d("test", "Nested -> execute") } } } // 调用 Outter.Nested().execute() //输出 Nested -> execute
2)内部类
内部类需要使用关键字inner修饰
class Outter{ val testVal = "test" inner class Inner{ fun execute(){ Log.d("test", "Inner -> execute : can read testVal=$testVal") } } } // 调用 val outter = Outter() outter.Inner().execute() // 输出 Inner -> execute : can read testVal=test //可以读取到testVal的值,即外部类中的值
compare:
嵌套类中可以直接创建实例val nested : Outter.Nested()
内部类不能直接创建实例,需要通过外部类调用
val outter = Outter() outter.Inner().execute()
嵌套类不能引用包装类的成员,内部类会带有一个对外部包装类的对象的引用,可以访问外部类中的成员属性和成员函数(如上面例子中的testVal)。
匿名内部类(自定类,实现方法logic,然后再在新类的主程序中调用)
当然还有其他匿名内部类的实现方式,
java中的参考:http://www.cnblogs.com/nerxious/archive/2013/01/25/2876489.html
class Num{ fun logic(a:Int,b:Int){ println("a:$a,b:$b") } } fun main(args: Array<String>){ val num = Num() num.logic(1,2) } //输出 a:1,b:2
11、类委托和委托属性
委托模式是最常用的设计模式的一种,在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。1)类委托
interface Base{ fun print() } class BaseImpl(val x : Int) :Base{ override fun print(){ Log.d(JTAG, "BaseImpl -> ${x.string()}") } } class Printer(b : Base) : Base by b fun test(){ val b = BaseImpl(5) Printer(b).print() } //输出 BaseImpl -> 5
Printer没有实现接口Base的方法print(),而是通过关键字by,将实现委托给了b,而输出也和预想的一样。
2)委托属性
语法:val/var <属性名>: <类型> by <表达式>
在 by 后面的表达式是该 委托, 因为属性对应的 get()(和 set())会被委托给它的 getValue() 和 setValue() 方法。 属性的委托不必实现任何的接口,但是需要提供一个 getValue() 函数(和 setValue()——对于 var 属性)。
class Example{ //委托类 var property : String by DelegateProperty() } class DelegateProperty{ //被委托类 var temp = "old" operator fun getValue(ref: Any?,p:KProperty<*>):String{ return "DelegateProperty --> ${p.name} --> $temp" } operator fun setValue(ref: Any?, p: KProperty<*>, value: String){ //setValue方法只有委托属性为var时存在,委托属性为val时不存在该方法 temp = value } } fun test(){ val e = Example() Log.d(JTAG, e.property) e.property = "new" Log.d(JTAG, e.property) } // 输出 DelegateProperty --> property --> old DelegateProperty --> property --> new
注:
1、如果委托属性是只读属性,暨val,则被委托类需要实现getValue方法
2、如果委托属性是可变属性,暨var,则被委托类需要实现getValue方法和setValue方法
3、getValue方法的返回类型必须是与委托属性相同或是其子类
4、getValue方法和setValue方法必须要用关键字operator 标记
3)委托属性
三种标准委托属性
延迟属性、可观察属性、map属性
延迟属性:
只有在第一调用的时候才会初始化,在定义的时候不进行初始化
val lazyValue: String by lazy { Log.d(JTAG, "Just run when first being used") "value" } fun test(){ Log.d(JTAG, lazyValue) Log.d(JTAG, lazyValue) } // 输出 Just run when first being used value value
可观察属性:
可观察属性对应的是我们常用的观察者模式
class User { var name: Int by Delegates.observable(0) { prop, old, new -> Log.d(JTAG, "$old -> $new") } var gender: Int by Delegates.vetoable(0) { prop, old, new -> (old < new) } } fun test(){ val user = User() user.name = 2 // 输出 0 -> 2 user.name = 1 // 输出 2 -> 1 user.gender = 2 Log.d(JTAG, user.gender.string()) // 输出 2 user.gender = 1 Log.d(JTAG, user.gender.string()) // 输出 2 }
Delegates.observable() 接受两个参数:初始值和修改时处理程序(handler)。该方法是在被赋值且执行完set方法后才被执行;
Delegates.vetoable()该方法在set执行之前被触发,它返回一个Boolean,如果为true才会继续执行set;否则保持原值。
如上例:第一次赋值 user.gender = 2时,由于2>0,所以old
map映射:
可以使用映射实例自身作为委托来实现委托属性。
class User(val map: Map<String, Any?>) { val name: String by map val age: Int by map } val user = User(mapOf( "name" to "John Doe", "age" to 25 )) println(user.name) // Prints "John Doe" println(user.age) // Prints 25
这也适用于 var 属性,如果把只读的 Map 换成 MutableMap 的话:
class MutableUser(val map: MutableMap<String, Any?>) { var name: String by map var age: Int by map }
12、函数式编程
class Number{ //声明函数 fun sum(a:Int,b:Int) = a + b //声明方法 fun logic(a:Int,b:Int,calc:(Int,Int) -> Int){ println("calc : ${calc(a,b)}") } } fun main(args:Array<String>){ val num = Number() num.logic(1,2,num::sum) } //输出 calc : 3
格式: 参数名: (参数类型,参数类型…) -> 输出类型
参数名不一定是方法名,参数类型是这个函数参数的输入类型,如果是无参函数,括号()不可省略!
返回结果用函数返回
class Number{
//声明函数
fun sum(a:Int,b:Int) = a + b
//声明方法
fun logic(a:Int,b:Int,calc:(Int,Int) -> Int){
println(“calc : ${calc(a,b)}”)
}
//调用函数方法返回结果
fun getSumMethod() = this::sum
}
fun main(args:Array<String>){ val num = Number() num.logic(1, 2, num.getSumMethod()) } //输出 calc : 3
kotlin中函数可作为一个普通的类,一个参数,一个返回,剩下一个实现方法调用
13、Lambda的使用
class Number{ //声明方法 fun logic(a:Int,b:Int,calc:(Int,Int) -> Int){ println("calc : ${calc(a,b)}") } } fun main(args:Array<String>){ val num = Number() num.logic(1,2,{x,y -> x+y}) } //输出 calc : 3
Lambda方式:num.logic(1, 2, {x,y -> x+y})
注:
Lambda表达式总是被大括号{}包围着
函数体跟在 -> 右边,左侧是参数,多个参数用逗号,分割
当函数数字面值只有一个参数,它的声明可以省略(连同 ->),名称为it;而当函数是无参函数时,主程序中调用时也可省略 ->
单参函数:
fun oneParams(one : (Int) -> Int){ println("oneParams : ${one(5)}") } fun main(args : Array<String>){ val num = Num() num.oneParams({it*2}) } //输出 oneParams : 10
无参函数:
fun empty(emptyM : () -> Unit){ emptyM() } fun main(args : Array<String>){ val num = Num() num.empty({println("empty method")}) } //输出 empty method
当函数中有某个参数没有用到,可以使用下划线_代替。
fun unusedParams(unused : (Int,Int) -> Int){ println("unusedParams : ${unused(5,10)}") } fun main(args : Array<String>){ val num = Num() num.unusedParams{ _,used -> used*2 } } //输出 unusedParams : 20
当函数中最后一个参数是一个函数时,可以把它放在括号()外面
class Num { fun logic(a: Int, b: Int, calc: (Int, Int) -> Int){ println("calc : ${calc(a,b)}") } fun sum(a: Int, b: Int) = a + b } fun main(args : Array<String>){ val num = Num() // 写法1 num.logic(1, 2, {x : Int,y : Int -> x+y}) // 写法2 num.logic(1, 2){x : Int,y : Int -> x+y} // 写法3 num.logic(1, 2){x,y -> x+y} } //如果有多行数据时: num.logic(1, 2, {x,y -> println("extra line") x+y }) num.logic(1, 2){x,y -> println("extra line") x+y }
匿名函数
fun(x: Int, y: Int): Int = x + y fun(x: Int, y: Int): Int {return x + y}
Lambda 表达式或者匿名函数(以及局部函数和对象表达式) 可以访问其 闭包 ,即在外部作用域中声明的变量。 与 Java 不同的是可以修改闭包中捕获的变量:
var sum = 0 ints.filter { it > 0 }.forEach { sum += it } print(sum)
还有待持久性的学习巩固最新知识,更多高级应用期待你们的分享。
相关文章推荐
- Kotlin 基本语法 (一)
- DataBinding In Kotlin编译不通过
- Kotlin入门第一课
- Kotlin 第二弹:Android 中 PDF 创建与渲染实践
- Kotlin 语法
- Kotlin资料
- 使用Kotlin优雅的开发Android应用,附demo
- 【DOC】Kotlin 数组 Array
- Kotlin实现静态方法
- Kotlin : 学习笔记一
- Kotlin 博客 基础语法学习笔记
- Kotlin基础教程-返回值和跳转
- Kotlin Reference (四) control flow
- kotlin汇总6-函数
- Kotlin Getting Started
- kotlin---使用注释处理的 Android 框架
- Kotlin Reference (五) 类的构造函数,类的继承,属性操作
- Kotlin版LogUtil
- kotlin结合dagger2使用为什么在编译时无法自动生成DaggerxxxComponent类
- android kotlin其它(一)解构声明