1. 1. Kotlin学习笔记0x03
    1. 1.1. 标签
    2. 1.2. 标签的格式为标识符后加上一个@ 例如a@,b@ 标签可以用于控制return break continue的跳转行为12345678910111213141516171819202122fun main(args: Array<String>) { returnDemo()}fun returnDemo(){ println("Start "+::returnDemo.name)//打印当前开始的函数的名称 val intArray = intArrayOf(1,2,3,4,5) intArray.forEach here@{//在这里设置一个名为here的标签 if(it == 3){ return@here } println(it)//打印循环到的内容,it代指当前循环内容 } /*因为接受该Lambda表达式的函数是forEach,所以可以直接使用return@forEach 跳转到下次循环 return@forEach实例 intArray.forEach{//在这里设置一个名为here的标签 if(it == 3){ //return@forEach } println(it)//打印循环到的内容,it代指当前循环内容 }*/ println("End "+::returnDemo.name)//打印当前结束的函数的名称}123456Start returnDemo1245End returnDemoLambda函数/Lambda表达式break配合@标识符 结束嵌套的for循环1234567891011121314151617fun main(args: Array<String>) { breakDemo()}fun breakDemo(){ println("----------") outer@ for(outer in 1..5){ for(inner in 1..10){ println("inner=$inner") println("outer=$outer") if(inner % 2==0){ break@outer//直接结束外部for循环 //break //结束break 所在的循环(inner) } } } println("**********")}123456----------inner=1outer=1inner=2outer=1**********为了代码可读性,可以显示的用标识符来表示所要跳转的循环体```Kotlinfun main(args: Array) { breakDemo2()}fun breakDemo2() { println(“———-“) outer@ for(outer in 1..5){ inner@ for(inner in 1..10){ print(“outer=$outer,”) println(“inner=$inner”) if(inner % 2==0){ break@inner //break@outer } } } println(“**********”)}123456789101112131415161718````Kotlin----------outer=1,inner=1outer=1,inner=2outer=2,inner=1outer=2,inner=2outer=3,inner=1outer=3,inner=2outer=4,inner=1outer=4,inner=2outer=5,inner=1outer=5,inner=2**********//break@outer的情况----------outer=1,inner=1outer=1,inner=2**********
    3. 1.3. throw表达式
    4. 1.4. 在代码中使用Nothing来标记无返回的函数1234fun main(args: Array<String>) { fail("s")}fun fail(msg:String):Nothing{throw IllegalArgumentException("at fail($msg)")}123Exception in thread "main" java.lang.IllegalArgumentException: at fail(s) at com.easy.kotlin.A_multi_language_HelloKt.fail(A multi-language Hello.kt:9) at com.easy.kotlin.A_multi_language_HelloKt.main(A multi-language Hello.kt:7)throw表达式的值可以付给变量,但需要显式的声明类型为Nothing,这个变量也无法当作参数参数传给函数1234fun main(args: Array<String>) { val ex: Nothing = throw Exception("EX") println(ex)}1234567891011Error: Overload resolution ambiguity: @InlineOnly public inline fun println(message: Any?): Unit defined in kotlin.io@InlineOnly public inline fun println(message: Boolean): Unit defined in kotlin.io@InlineOnly public inline fun println(message: Byte): Unit defined in kotlin.io@InlineOnly public inline fun println(message: Char): Unit defined in kotlin.io@InlineOnly public inline fun println(message: CharArray): Unit defined in kotlin.io@InlineOnly public inline fun println(message: Double): Unit defined in kotlin.io@InlineOnly public inline fun println(message: Float): Unit defined in kotlin.io@InlineOnly public inline fun println(message: Int): Unit defined in kotlin.io@InlineOnly public inline fun println(message: Long): Unit defined in kotlin.io@InlineOnly public inline fun println(message: Short): Unit defined in kotlin.io
    5. 1.5. this 关键字
    6. 1.6. this 表示当前对象的引用,我们可以使用this来引用变量或者成员函数,也可以使用return来返回某个类的引用12345678910111213141516fun main(args: Array<String>) { val demo = ThisDemo() println(demo.whatIsThis())}class ThisDemo{ val thisis="THIS IS" fun whatIsThis():ThisDemo{ println(this.thisis) this.howIsThis() return this } fun howIsThis(){ println("HOW IS THIS?") }}123THIS ISHOW IS THIS?com.easy.kotlin.ThisDemo@5305068a在扩展函数或者带接收者的函数字面值中,this表示在点左侧传递的接受者参数123456fun main(args: Array<String>) { val sum = fun Int.(x: Int)=this+x println(1.sum(2)) val str = fun String.(s:String)=this+s println("old".str("new"))}123oldnew如果this没有限定符,那么它指的就是最内层包含它的作用域,如果想要引用其他作用于中的this,可以使用this@label标签123456789101112131415161718192021222324252627282930class Outer{ val oh ="Oh" inner class Inner{ fun m(){ val outer = this@Outer val inner = this@Inner val pthis =this println("outer="+outer) println("inner="+inner) println("pthis="+pthis) println(this@Outer.oh) val fun1 = hello@ fun String.(){ val d1 = this println("d1"+d1) } val fun2={s:String-> val d2 = this println("d2=$d2") } "abc".fun1() fun2 } }}fun main(args:Array<String>){ val outer = Outer() outer.Inner().m()}12345outer=com.easy.kotlin.Outer@5305068ainner=com.easy.kotlin.Outer$Inner@1f32e575pthis=com.easy.kotlin.Outer$Inner@1f32e575Ohd1abc
    7. 1.7. super关键字
    8. 1.8. 敲到这里 我突然产生了一个疑问,我也不知道我打字的时候是盲打还是看着打的 至少符号多数是看着打的然后我就去百度下 其他人敲代码是盲打还是看着打,然后,看到了一个 关于盲人敲代码的文章盲人程序员是如何编程的文章的最后提到了 盲人做梦…勾起了我的好奇心123456789101112131415161718192021222324252627282930open class Father{ open val firstName = "Chen" open val lastName ="Jason" fun ff(){ println("FFF") }}class Son:Father{ //Son继承Father override var firstName = super.firstName override var lastName = "Jack" constructor(){ //空的构造函数 } constructor(lastName:String){ //带有一个参数的构造函数 this.lastName = lastName } fun love(){ super.ff()//调用父类的ff函数 println(super.firstName+" "+super.lastName+" Love "+this.firstName+" "+this.lastName) }}fun main(args:Array<String>){ val son1 = Son("Harry")//手动的为lastName进行了赋值操作 val son2 = Son()//lastName将会采用默认的Jack son1.love()//son1的名字是Chen Harry son2.love()//son2的名字是Chen Jack}1234FFFChen Jason Love Chen HarryFFFChen Jason Love Chen Jack
    9. 1.9. 运算符的重载
      1. 1.9.1. 运算符 - 的重载
      2. 1.9.2. 运算符 + 的重载
    10. 1.10. in操作符
    11. 1.11. 索引访问操作符
    12. 1.12. 调用操作符
    13. 1.13. 计算并赋赋值
    14. 1.14. Elvis 操作符 ?:
    15. 1.15. 比较操作符
    16. 1.16. infix函数自定义中缀操作符
    17. 1.17. 函数扩展和属性扩展
      1. 1.17.1. 扩展函数
      2. 1.17.2. 扩展属性
    18. 1.18. 空指针安全
  2. 2. To Be Continue

Code Kotlin学习笔记0x03

Kotlin学习笔记0x03

标签

标签的格式为标识符后加上一个@ 例如a@,b@
标签可以用于控制return break continue的跳转行为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fun main(args: Array<String>) {
returnDemo()
}
fun returnDemo(){
println("Start "+::returnDemo.name)//打印当前开始的函数的名称
val intArray = intArrayOf(1,2,3,4,5)
intArray.forEach here@{//在这里设置一个名为here的标签
if(it == 3){
return@here
}
println(it)//打印循环到的内容,it代指当前循环内容
}
/*因为接受该Lambda表达式的函数是forEach,所以可以直接使用return@forEach 跳转到下次循环
return@forEach实例
intArray.forEach{//在这里设置一个名为here的标签
if(it == 3){
//return@forEach
}
println(it)//打印循环到的内容,it代指当前循环内容
}*/
println("End "+::returnDemo.name)//打印当前结束的函数的名称
}

1
2
3
4
5
6
Start returnDemo
1
2
4
5
End returnDemo

Lambda函数/Lambda表达式

break配合@标识符 结束嵌套的for循环
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fun main(args: Array<String>) {
breakDemo()
}
fun breakDemo(){
println("----------")
outer@ for(outer in 1..5){
for(inner in 1..10){
println("inner=$inner")
println("outer=$outer")
if(inner % 2==0){
break@outer//直接结束外部for循环
//break //结束break 所在的循环(inner)
}
}
}
println("**********")
}

1
2
3
4
5
6
----------
inner=1
outer=1
inner=2
outer=1
**********

为了代码可读性,可以显示的用标识符来表示所要跳转的循环体
```Kotlin
fun main(args: Array) {
breakDemo2()
}
fun breakDemo2() {
println(“———-“)
outer@ for(outer in 1..5){
inner@ for(inner in 1..10){
print(“outer=$outer,”)
println(“inner=$inner”)
if(inner % 2==0){
break@inner
//break@outer
}
}
}
println(“**********”)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
````Kotlin
----------
outer=1,inner=1
outer=1,inner=2
outer=2,inner=1
outer=2,inner=2
outer=3,inner=1
outer=3,inner=2
outer=4,inner=1
outer=4,inner=2
outer=5,inner=1
outer=5,inner=2
**********
//break@outer的情况
----------
outer=1,inner=1
outer=1,inner=2
**********

throw表达式

在Kotlin中throw是表达式,它的类型是Nothing,这种类型没有值,与C Java中的void 具有相同的意思

在代码中使用Nothing来标记无返回的函数
1
2
3
4
fun main(args: Array<String>) {
fail("s")
}
fun fail(msg:String):Nothing{throw IllegalArgumentException("at fail($msg)")}

1
2
3
Exception in thread "main" java.lang.IllegalArgumentException: at fail(s)
at com.easy.kotlin.A_multi_language_HelloKt.fail(A multi-language Hello.kt:9)
at com.easy.kotlin.A_multi_language_HelloKt.main(A multi-language Hello.kt:7)

throw表达式的值可以付给变量,但需要显式的声明类型为Nothing,这个变量也无法当作参数参数传给函数
1
2
3
4
fun main(args: Array<String>) {
val ex: Nothing = throw Exception("EX")
println(ex)
}

1
2
3
4
5
6
7
8
9
10
11
Error: Overload resolution ambiguity: 
@InlineOnly public inline fun println(message: Any?): Unit defined in kotlin.io
@InlineOnly public inline fun println(message: Boolean): Unit defined in kotlin.io
@InlineOnly public inline fun println(message: Byte): Unit defined in kotlin.io
@InlineOnly public inline fun println(message: Char): Unit defined in kotlin.io
@InlineOnly public inline fun println(message: CharArray): Unit defined in kotlin.io
@InlineOnly public inline fun println(message: Double): Unit defined in kotlin.io
@InlineOnly public inline fun println(message: Float): Unit defined in kotlin.io
@InlineOnly public inline fun println(message: Int): Unit defined in kotlin.io
@InlineOnly public inline fun println(message: Long): Unit defined in kotlin.io
@InlineOnly public inline fun println(message: Short): Unit defined in kotlin.io

this 关键字

this 表示当前对象的引用,我们可以使用this来引用变量或者成员函数,也可以使用return来返回某个类的引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fun main(args: Array<String>) {
val demo = ThisDemo()
println(demo.whatIsThis())
}

class ThisDemo{
val thisis="THIS IS"
fun whatIsThis():ThisDemo{
println(this.thisis)
this.howIsThis()
return this
}
fun howIsThis(){
println("HOW IS THIS?")
}
}

1
2
3
THIS IS
HOW IS THIS?
com.easy.kotlin.ThisDemo@5305068a

在扩展函数或者带接收者的函数字面值中,this表示在点左侧传递的接受者参数
1
2
3
4
5
6
fun main(args: Array<String>) {
val sum = fun Int.(x: Int)=this+x
println(1.sum(2))
val str = fun String.(s:String)=this+s
println("old".str("new"))
}

1
2
3
oldnew

如果this没有限定符,那么它指的就是最内层包含它的作用域,如果想要引用其他作用于中的this,可以使用this@label标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Outer{
val oh ="Oh"

inner class Inner{
fun m(){
val outer = this@Outer
val inner = this@Inner
val pthis =this
println("outer="+outer)
println("inner="+inner)
println("pthis="+pthis)
println(this@Outer.oh)

val fun1 = hello@ fun String.(){
val d1 = this
println("d1"+d1)
}
val fun2={s:String->
val d2 = this
println("d2=$d2")
}
"abc".fun1()
fun2
}
}
}
fun main(args:Array<String>){
val outer = Outer()
outer.Inner().m()
}

1
2
3
4
5
outer=com.easy.kotlin.Outer@5305068a
inner=com.easy.kotlin.Outer$Inner@1f32e575
pthis=com.easy.kotlin.Outer$Inner@1f32e575
Oh
d1abc

super关键字

super关键字指向其父类的引用

敲到这里 我突然产生了一个疑问,我也不知道我打字的时候是盲打还是看着打的 至少符号多数是看着打的
然后我就去百度下 其他人敲代码是盲打还是看着打,
然后,看到了一个 关于盲人敲代码的文章盲人程序员是如何编程的
文章的最后提到了 盲人做梦…勾起了我的好奇心
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
open class Father{
open val firstName = "Chen"
open val lastName ="Jason"

fun ff(){
println("FFF")
}
}
class Son:Father{
//Son继承Father
override var firstName = super.firstName
override var lastName = "Jack"
constructor(){
//空的构造函数
}
constructor(lastName:String){
//带有一个参数的构造函数
this.lastName = lastName
}
fun love(){
super.ff()//调用父类的ff函数
println(super.firstName+" "+super.lastName+" Love "+this.firstName+" "+this.lastName)
}
}
fun main(args:Array<String>){
val son1 = Son("Harry")//手动的为lastName进行了赋值操作
val son2 = Son()//lastName将会采用默认的Jack
son1.love()//son1的名字是Chen Harry
son2.love()//son2的名字是Chen Jack
}

1
2
3
4
FFF
Chen Jason Love Chen Harry
FFF
Chen Jason Love Chen Jack

运算符的重载

表达式 对应的函数
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()
a+b a.plus(b)
a-b a.minus(b)
a*b a.times(b)
a/b a.div(b)
a%b a.rem(b),a.mod(b)
a..b a.rangeTo(b)

表达式 对应的函数 返回值
a++ a.inc() a
a— a.dec() a
++a a.inc() a+1
—a a.dec() a-1

运算符 - 的重载

1
2
3
4
5
6
7
8
data class Point(val x: Int, val y: Int)
operator fun Point.unaryMinus() = Point(-x, -y)

fun main(args:Array<String>){
val p = Point(6, 7)
val np= -p
println(np) //Point(x=-1, y=-1)
}
1
Point(x=-6, y=-7)

运算符 + 的重载

1
2
3
4
5
6
7
8
9
10
data class Point(val x: Int, val y: Int)
operator fun Point.plus(increment: Int):Point=Point(x+increment,y+increment)
operator fun Point.plus(inc: Point):Point = Point(x+inc.x,y+inc.y)
fun main(args:Array<String>){
val p = Point(6, 7)
val np= p+1
val np2 = p+p
println(np) //Point(x=-1, y=-1)
println(np2)//Point(x=12, y=14)
}
1
2
Point(x=7, y=8)
Point(x=12, y=14)

in操作符

表达式 对应函数
a in b b.contains(a)
a !in b !b.contains(a)

索引访问操作符

表达式 对应函数
a[i] a.get(i)
a[i] a.set(i,b)

调用操作符

表达式 对应函数
a() a.invoke()
a(i) a.invoke(i)

计算并赋赋值

表达式 对应函数
a+=b a.plusAssign(b)
a-=b a.minusAssign(b)
a/=b a.divAssign(b)
a*=b a.timesAssign(b)
a%=b a.modAssign(b)

Elvis 操作符 ?:

在Kotlin中,Elvis操作符特定是跟null进行比较

1
2
3
y = x?:0
//等价于
val y = if(x!=null)x else 0

主要用作 null 安全检查
Elvis操作符的命名灵感来自于猫王的发型风格,不过我去百度了下猫王(埃尔维斯·普雷斯利Elvis Presley),感觉没多大联系,Kotlin创造者的想法真是奇怪
Kotlin中并没有xxx?true:false这样的三元运算符取而代之的是if(true) true else false

比较操作符

表达式 对应函数
a>b a.compareTo(b) > 0
a<b a.compareTo(b) < 0
a>=b a.compareTo(b) >= 0
a<=b a.compareTo(b) <= 0
compareTo返回一个Int值

infix函数自定义中缀操作符

1
2
3
4
5
6
7
8
9
data class Person(val name:String,val age: Int)
infix fun Person.grow(years:Int):Person{
return Person(name,age+years)
}
fun main(args:Array<String>){
val person = Person("Jack",11)
println(person.grow(1))
println(person grow 9)
}
1
2
Person(name=Jack, age=12)
Person(name=Jack, age=20)

你可能会觉得 这个调用一个类内部函数没多大区别啊,别急看看下面的例子

1
2
3
4
5
6
7
8
9
10
infix fun Int.a(x:Int)=this+x
infix fun String.说(s:String)=this+s
fun main(args:Array<String>){
println(10.a(1))
println(1 a 2)
println("你拍一".说(",我拍二"))
println("你拍二"",我还是拍一")
val 我的天啊 = "不存在的"
println(我的天啊)
}
1
2
3
4
5
11
3
你拍一,我拍二
你拍二,我还是拍一
不存在的

是的 就是有这种操作


函数扩展和属性扩展

Kotlin 支持 扩展函数 和 扩展属性.能够扩展一个类的新功能而无需继承该类
,大多数情况下我们在顶层定义扩展,即直接在包里

1
2
3
4
5
6
package com.easy.kotlin

val <T> List<T>.lastIndex: Int get() = size -1
fun String.notEmpty():Boolean{
return !this.isEmpty()
}

若要使用其他包的扩展,我们需要在调用方内导入它

1
2
3
4
5
6
7
package com.example.usage
import foo.bar.goo
import foo.bar.*

fun uage(baz: Baz){
baz.goo()
}

扩展函数

1
2
3
4
5
6
7
//对于双重否定的逻辑判断,我们可以对齐扩展出一个函数
fun String.notEmpty():Boolean=!this.isEmpty()
fun main(args:Array<String>){
println("a".notEmpty())
println(!"123".isEmpty())
}
//
1
2
true
true

看到这里,你能会想,这个扩展函数和infix函数有啥区别的,碰巧的是,我也有这样疑问,于是做了个试验,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fun main(args:Array<String>){
println("a".notEmpty("cct",2))
println("a".notEmpty())
//println("a" notEmpty "asd"))
println("b" isnotEmpty "asd")
println("b".isnotEmpty("asd"))
//可以通过编译并且执行
}
fun String.notEmpty():String{
return this+":String.notEmpty()"
}
fun String.notEmpty(s:String,n:Int):String{
return this+s+":String.notEmpty(s:String)"+n.toString()
}
infix fun String.isnotEmpty(s:String):String{
return this +s+":String.isnotEmpty(s:String)"
}
// infix fun String.isnotEmpty():String{
// return this + ":String.isnotEmpty(s:String)"
// }
//非法函数
1
2
3
4
acct:String.notEmpty(s:String)2
a:String.notEmpty()
basd:String.isnotEmpty(s:String)
basd:String.isnotEmpty(s:String)

infix 函数有且只有一个参数,拓展函数可以有任意个参数,只有用infix符号修饰的函数才可以实现中缀操作符调用(例如”b” isnotEmpty “asd”)


扩展属性

1
2
3
4
5
6
7
8
fun main(args:Array<String>){
val mList = mutableListOf<Int>(100,200,300,400,500)
println(mList)
println(mList.lastIndex)//本应该返回5,但是因为下面对lastIndex进行了扩展,所以输出了-5
}
val <T> List<T>.lastIndex: Int get(){
return -size
}
1
2
[100, 200, 300, 400, 500]
-5

空指针安全

在Kotlin中 null 等同于空指针
一个非空引用不能直接复制为空
对于非空引用,可以直接调用它的方法或者访问它的属性

如果允许为空,就得在变量类型后面加上一个?表示这个变量允许为空
对于允许为空的引用,不能直接调用他的方法和属性,得使用安全调用(使用.?)或者非空断言调用(或者使用!!.)

1
2
3
4
5
6
7
8
9
10
11
fun main(args:Array<String>){
var s1: String="s"
var s2: String?
s2=null//合法
//s1=null//非法
println(s1.length)//合法
println(s2)
println(s2?.length)
println(s2!!.length)
//println(s2.length)//非法
}
1
2
3
4
5
6
7
1
null
null

Exception in thread "main" kotlin.KotlinNullPointerException
at com.easy.kotlin.A_multi_language_HelloKt.main(A multi-language Hello.kt:16)

参考资料

在线Kotlin IDE

To Be Continue

阅读量: