高级特性
1、解构
class User(var age:Int,var name:String){
//operator将一个函数标记为重载一个操作符或者实现一个约定
operator fun component1() = age
operator fun component2() = name
}
fun main() {
var user = User(12,"aaa")
var (age,name) = user
}
在赋值的时候 调用component1和2这两个方法赋值给第一个、第二个元素。
解构更常见于map:
fun main() {
var map = mapOf<String,String>("1" to "key1","2" to "key2")
for((k,v) in map){
println("key:$k,value:$v")
}
}
2、循环和集合操作符
五种循环语法:
fun main() {
for(i in 1..10){
println(i)
}
for(i in 1 until 10){
println(i)
}
for(i in 10 downTo 1){
println(i)
}
for(i in 1..10 step 2){
}
repeat(10){
println(it)
}
}
遍历集合:
fun main() {
var list = arrayListOf<String>("a","b","c")
for(str in list){
println(str)
}
for((index,str) in list.withIndex()){
println("$index ,,, $str")
}
}
3、集合操作符:
fun main() {
var list = arrayListOf<Char>('a','b','c','d')
//返回符合条件的第一个
val a = list.map { it - 'a' }.filter { it > 0 }.find { it > 1 }
}
fun demo(){
var a = arrayOf("4","0","i","f","w","0","9")
var index = arrayOf(5,3,9,4,8,31,9,2,1,7)
index.filter {
it < a.size
}.map {
a[it]
}.reduce{
s , s1 -> "$s$s1"
}.also {
println(it)
}
}
filter就像过滤器一样,筛选出符合条件的。map是可以改变返回的数据类型的,原先返回值是int,现在返回值是String。reduce可以取出两个拼接字符串,最后also输出结果。
常用操作符:
4、作用域函数
fun main() {
val user = User("zhangsan")
//let和run都会返回闭包的执行结果,区别在于let闭包有参数,而run闭包没有参数
var letResult:String = user.let { user:User -> "let::${user.javaClass}" }
println(letResult)
var runResult:String = user.run { "run::${this.javaClass}" }
//also与apply都不返回闭包的执行结果,区别在于also有闭包参数,而apply没有闭包参数
user.also {
println("also::${it.javaClass}")
}
user.apply {
println("apply::${this.javaClass}")
}
//takeIf的闭包返回一个判断结果,为false时,takeIf函数会返回null
//takeUnless 与 takeIf刚好相反,闭包的判断结果,为true时,函数返回null
user.takeIf { it.name.length > 0 }?.also { println("name:${it.name}") } ?: println("name:null")
user.takeUnless { it.name.length > 0 }?.also { println("name:null") } ?: print("name:${user.name}")
//重复执行当前闭包
repeat(5){
println(user.name)
print(it)
}
//with比较特殊,是一个顶级函数,与下面的apply类似
with(user){
this.name = "with"
}
//user.apply { this.name = "with" }
5、中缀表达式
fun main() {
for(i in 1..100 step 20){
println(i)
}
}
//实际上这个代码在编译后就变成了一个方法,来帮我们实现这样的一种简写,这个就是运算符重载
//通过operator实现,rangeTo的方法
手写一个中缀表达式:
fun main() {
println(5 vs 6)
}
sealed class CompareResult{
object LESS:CompareResult(){
override fun toString(): String {
return "小于"
}
}
object MORE:CompareResult(){
override fun toString(): String {
return "大于"
}
}
object EQUAL:CompareResult(){
override fun toString(): String {
return "等于"
}
}
}
infix fun Int.vs(num:Int):CompareResult =
if(this - num < 0){
CompareResult.LESS
}else if(this - num > 0){
CompareResult.MORE
}else{
CompareResult.EQUAL
}
用infix关键字定义运算符重载函数
6、DSL(领域专用语言:json、xml..巴拉巴拉)
自己感兴趣可以查一查。
7、val和var的本质区别
var 对象实际上是拥有getter和setter方法的,val是没有setter方法的,但是我们可以重写get方法达到某种变得目的。
这个是var修饰得数据:
class demo{
var a:Int = 1
set(value){
field = value
}
get(){return field}
}
这里面set得时候不可以用a=value,因为只要用a=xx这个变量就会触发set方法。就会一直递归造成栈溢出。
val修饰得数据:
class demo{
val a:Int = 1
get(){return field}
}
fun main() {
var demo:Demo = Demo()
println(demo.a)
demo.countAdd()
println(demo.a)
}
class Demo{
var count = 1;
val a:Int = 1
get(){return field + count}
fun countAdd(){
count++;
}
}
我们可以在get上面做手脚达到可变的目的。输出2、3。如果我们真想用常量,可以试着用const val关键字。
const val b:Int = 1;
class Demo{
companion object {
const val a:Int = 1;
}
}
这个const只能修饰在object里面,也就是我们的单例对象和类的外边。const val只能修饰基本数据类型和String类型,在编译期就可以知道类型的数据。
8、内联noinline
kotlin规定:内部lambda是不允许中断外部执行的。
而inline是可以的:
fun main() {
test {
print("aaaaa")
return
}
print("bbbbb")
}
inline fun test(l : () -> Unit){
l.invoke()
}
只会打印aaaaa,这是不行的。如果我们去掉inline呢?
fun main() {
test {
print("aaaaa")
return@test
}
print("bbbbb")
}
fun test(l : () -> Unit){
l.invoke()
}
kotlin就会让我们return@test,表示执行完这个闭包,打印aaaaa、bbbbb。
fun main() {
test {
print("aaaaa")
return@test
print("ccccc")
}
print("bbbbb")
}
inline fun test(crossinline l : () -> Unit){
l.invoke()
}
如果我们想要有inline还得输出aaaaa,bbbbb。就只能像上面这样做了。
9、泛型
class Test<T> where T:Runnable{
fun add(t:T){
t.run()
}
}
声明T必须是Runnable的一个子类。