• Kotlin进阶学习3


    写在前面

    本文上接:Kotlin进阶学习2,在上次的文章里,我们学习了高阶函数。这次我们就来学习如何利用高阶函数简化Android中的各种常见操作,并且学习一下泛型的内容。

    使用高阶函数简化Android开发

    既然谷歌一直推荐使用Kotlin作为安卓开发的语言,那么谷歌肯定为我们提供了各种方便使用Kotlin开发的库。接下来我们就尝试自己实现其中的一些功能,以加固高阶函数的理解。

    简化SharedPreferences的用法

    在学习如何简化之前,先来看看SharedPreferences的基本用法:

    • 调用SharedPreferences的edit()方法获得SharedPreferences.Editor对象
    • 向SharedPreferences.Editor()对象中添加数据
    • 调用apply方法将添加的数据提交,完成数据存储。

    在了解了基本用法后,我们就可以尝试用高阶函数来改写了:

    fun SharedPreferences.open(block:SharedPreferences.Editor.() -> Unit){
        val editor = edit()
        editor.block()
        editor.apply()
    }
    

    这段代码不是很难理解。首先我们通过扩展函数向SharedPreferences类中添加了一个open函数,且接收了一个函数类型的参数。由于在函数体内有了SharedPreferences的上下文,所以可以直接调用edit()方法获取SharedPreferences.Editor对象,最后调用我们传入的block()函数,提交即可。

    那么我们直接来使用一下吧:

    getSharedPreferences("data",Context.MODE_PRIVATE).open{
        putString("name","Tom")
        putInt("age",28)
    }
    

    因为这里的open函数里已经有了SharedPreferences.Editor的上下文了,所以可以直接调用一系列的put方法。

    当然,谷歌提供的KTX扩展库已经包含了上述的功能,且我们用kotlin创建项目时已经自动导入了该依赖:

    getSharedPreferences("data",Context.MODE_PRIVATE).edit{
        putString("name","Tom")
        putInt("age",28)
    }
    

    可以看到,除了函数名变成了edit之外,没有什么不同的地方。

    简化ContentValues的用法

    ContentValues的用法想必大家也不会陌生。主要用于在操作Sqlite数据库的存储和修改方法。具体用法这里就不再演示了,想必大家都知道。

    在开始之前,先补充一个小的知识点:在kotlin中使用A to B 这样的语法结构会创建一个Pair对象。具体的知识点我们将在下面补充。有了这个知识前提后,我们先来定义一个方法:

    fun cvOf(vararg pairs:Pair<String,Any?>):ContentValues{
        
    }
    

    这里的定义出现了很多新的词汇。首先是vararg,其实就是java里的可变参数列表。意思为我们允许向这个方法传入n个Pair类型的参数,这些参数都会赋值到这个pairs变量上,我们通过for循环就可以解析出来了。之后是Pair类型,Pair类型是一个键值对结构,比较值得庆幸的是ContentValues的key都是字符串类型,我们直接写String就可以了。但value却有很多种,这里的Any?中的Any是Kotlin中所有类的共同基类,类似Java中的Object类,问号表示允许传入空值。

    接下来就是逻辑部分:

    fun cvOf(vararg pairs:Pair<String,Any?>):ContentValues{
        val cv = ContentValues()
        for(pair in pairs){
            val key = pair.first
            val value = pair.second
            when(value){
                is Int -> cv.put(key,value)
                is Long -> cv.put(key,value)
                is Short -> cv.put(key,value)
                is Float -> cv.put(key,value)
                is Double -> cv.put(key,value)
                is Boolean -> cv.put(key,value)
                is String -> cv.put(key,value)
                is Byte -> cv.put(key,value)
                is ByteArray -> cv.put(key,value)
                null -> cv.putNull(key)
            }
        }
    }
    

    核心思路很简单,构建一个ContentValues()对象,然后循环遍历pairs,根据类型依次将数据put进去。需要注意的是,这里我们没有强转,因为这里使用了Koltin中的Smart Cast功能,比如when语句进入到Int条件分支后,value就会自动被转换成Int型,不再需要我们转换类型了。

    有了cvOf()函数后,我们直接来使用一下:

    val values = cvOf("name" to "Thrones","author" to "ee","pages" to 20,"price" to 20.85)
    db.insert("Book",null,values)
    

    当然,这里的cvOf()已经很好用了,但和高阶函数似乎没有啥关系。我们可以再优化一下:

    fun cvOf(vararg pairs:Pair<String,Any?>) = ContentValue().apply{
        for(pair in pairs){
            val key = pair.first
            val value = pair.second
            when(value){
                is Int -> put(key,value)
                is Long -> put(key,value)
                is Short ->put(key,value)
                is Float -> put(key,value)
                is Double -> put(key,value)
                is Boolean -> put(key,value)
                is String -> put(key,value)
                is Byte -> put(key,value)
                is ByteArray -> put(key,value)
                null -> putNull(key)
            }
        }
    }
    

    这样,不仅代码更加优雅,也充分运用了我们学习到的高阶函数。当然,KTX库也提供了类似的方法,函数名叫contentValuesOf,使用方法是一样的。

    泛型入门

    介绍

    泛型大家一定不会陌生,Java早就引入了泛型的机制,Kotlin更是很早就支持了泛型。篇幅原因,这里就先只学习一下泛型的基本用法。那什么是泛型呢?泛型其实就是允许我们在不指定具体类型的情况下进行编程,极大地方便了我们的开发和拓展。

    泛型主要有两种定义方式,泛型类和泛型方法。使用的语法结构都是,当然,T并不是固定的,只是我们约定俗成的一种写法。

    泛型类

    要定义一个泛型类,如下:

    class MyClass<T>{
        fun method (param:T) :T{
            return param
        }
    }
    

    可以看到,很简单也很方便。我们要使用的时候,直接这样就可以了:

    val myClass = Myclass<Int>()
    val result = myClass.method(123)
    

    泛型方法

    如果我们不想定义一个泛型类,可以直接定义一个泛型方法:

    class myClass{
    	fun <T> method(param:T):T{
        	return param
    	}
    }
    

    可以看到,我们只是把泛型声明写到了方法上而已。使用方法也就进行了改变:

    val myClass = MyClass()
    val result = myClass.method<Int>(123)
    

    其中,Kotlin还允许我们对泛型的类型进行限制,如果我们不想让泛型的类型指定为任意类型的话,可以规定他的上界:

    class myClass{
    	fun <T : Number> method(param:T):T{
        	return param
    	}
    }
    

    这里意思是说,我们的泛型只能输入数字类型的,如果指定成其他类型肯定会报错。

    另外,默认情况下所有泛型都是可以指定为可空类型的。因为默认上界是Any?,如果不想这样的话只要将上界改成Any就可以了。

    mapOf()函数里的to解析——infix函数

    之前,我们已经使用过很多次A to B这样的语法结构了。但to并不是一个关键字,能够实现这样的效果是因为Kotlin提供了一种语法糖特性:infix函数,这个函数也不难理解,比如A to B其实就是A.to(B)的写法。

    要学习这个函数,我们就从例子开始吧。String类中的startsWith()相信你一定用过,其可以用来判断一个字符串是否是由某个指定参数开头的。虽然这个函数用起来很简单,但我们借助infix函数可以让代码可读性更强:

    infix fun String.beginsWith(prefix:String) = startsWith(prefix)
    

    这个函数很好理解,就是定义了一个String类的拓展函数,其实现就是直接调用startsWith()函数。但加上了infix关键字后,我们就可以使用另一种方式调用这个函数了:

    if("Hello Kotlin" beginsWith "Hello")
    

    这样看来,infix函数其实也没什么大不了的,只是让代码更加易读了而已。

    那么我们直接打开to看看里面是如何实现的吧:

    可以看到,这里使用定义泛型的方式将to()函数定义到了A类型下,并接收一个B类型的参数。实现就更为简单了,直接构建了一个Pair类型对象,传入了A和B对象。也就是说,A to B 其实就是得到了一个包含了A和B数据的Pair对象。

    总结

    这次,我们学习了高阶函数与安卓结合的用法,对泛型做了一个简单的解释。同时也对infix关键字做了简单的介绍。总的来说本次学习是一个过渡,主要用来巩固之前的知识。接下来估计会学习泛型的进阶特性。

  • 相关阅读:
    测试面试题集-接口测试(9)
    测试面试题集-性能测试(8)
    测试面试题集-网络基础(7)
    测试面试题集-Python编程题(6)
    测试面试题集-Python列表去重(5)
    测试面试题集-生活物品测试:杯子、伞、钢笔、桌子、行李箱、电梯、洗衣机(4)
    测试面试题集-测试用例设计(3)
    测试面试题集-测试基础理论(2)
    解决在docker环境中拉取svn项目中含有中文名称的文件时拉取失败的问题
    redisTemplate之opsForHash()用法分析
  • 原文地址:https://www.cnblogs.com/wushenjiang/p/13470312.html
Copyright © 2020-2023  润新知