入门kotlin(下)

来源:互联网 发布:易语言电视直播源码 编辑:程序博客网 时间:2024/06/06 16:33

24.自定义的委托
举个例子,我们创建一个notNull的委托,它只能被赋值一次,如果第二次赋值,它就会抛异常。 Kotlin库提供了几个接口,我们自己的委托必须要实现:ReadOnlyProperty和ReadWriteProperty。具体取决于我们被委托的对象是val还是var。
步骤:
(1)创建一个类然后继承ReadWriteProperty:
private class NotNullSingleValueVar”<”T>() : ReadWriteProperty “”<”“Any?, T> { //get
override fun getValue(thisRef: Any?, property: KProperty”<”*>): T {
throw UnsupportedOperationException()
}
//set
override fun setValue(thisRef: Any?, property: KProperty”<”*>, value: T) {
} }
(2)实现这些函数。【委托可以作用在任何非null的类型。它接收任何类型的引用,然后像getter和setter那样使用T】

            private class NotNullSingleValueVar"<"T>() : ReadWriteProperty"<"Any?, T> {            private var value: T? = null                //Getter函数 如果已经被初始化,则会返回一个值,否则会抛异常。                override fun getValue(thisRef: Any?, property: KProperty"<"*>): T {                    return value ?: throw IllegalStateException("${desc.name} " +                            "not initialized")                }                //Setter函数 如果仍然是null,则赋值,否则会抛异常。                override fun setValue(thisRef: Any?, property: KProperty"<"*>, value: T) {                    this.value = if (this.value == null) value                    else throw IllegalStateException("${desc.name} already initialized")                }            }           (3)现在你可以创建一个对象,然后添加函数使用你的委托:            object DelegatesExt {                fun notNullSingleValue"<"T>():                        ReadWriteProperty"<"Any?, T> = NotNullSingleValueVar()            }                ------------------------也可以不继承===继承是override,不继承就是operator,其实不继承,自己写的话,也是写的被继承里面的逻辑------------                object DelegatesExt {                    fun "<"T> notNullSingleValue() = NotNullSingleValueVar"<"T>()                }                class NotNullSingleValueVar"<"T> {                    //var 可变;val  不可变   ? =不能为空                    private var value: T? = null                    operator fun getValue(thisRef: Any?, property: KProperty"<"*>): T {                        return value ?: throw IllegalStateException("${property.name} not initialized")                    }                    operator fun setValue(thisRef: Any?, property: KProperty"<"*>, value: T) {                        this.value = if (this.value == null) value                        else throw IllegalStateException("${property.name} already initialized")                    }                }

25.类中定义静态变量的代码块

companion object{ }

26.创建数据库

(1)导入库 compile “org.jetbrains.anko:anko-sqlite:$anko_version”
(2)添加引入 import org.jetbrains.anko.db.* (3)实现
ManagedSQLiteOpenHelper :SqliteOpenHelper只是一个工具,是SQL世界和OOP之间的一个通道
class ForecastDbHelper(ctx: Context = MyApp.instance) :
ManagedSQLiteOpenHelper(ctx, ForecastDbHelper.DB_NAME, null,
ForecastDbHelper.DB_VERSION) {
companion object {
val DB_NAME = “forecast.db”
val DB_VERSION = 1
/**
instance这个属性使用了lazy委托,它表示直到它真的被调用才会被创建。
用这种方法,如果数据库从来没有被使用,我们没有必要去创建这个对象。
一般lazy委托的代码块可以阻止在多个不同的线程中创建多个对象。
这个只会发生在两个线程在同事时间访问这个instance对象,它很难发生但是发生具体还有看app的实现。
无人如何,lazy委托是线程安全的。

              */              val instance by lazy { ForecastDbHelper() }          }          override fun onCreate(db: SQLiteDatabase) {              //(tableName: String, ifNotExists: Boolean = false,              // vararg columns: Pair"<"String, SqlType>) {              /*              第一个参数是表的名称              第二个参数,当是true的时候,创建之前会检查这个表是否存在。              第三个参数是一个Pair类型的vararg参数。              vararg也存在在Java中,这是一种在一个函数中传入联系很多相同类型的参数。              这个函数也接收一个对象数组。              */              //然而Anko提供了一个简单的扩展函数 createTable(),它接收一个表的名字和一系列由列名和类型构建的Pair对象:              db.createTable(CityForecastTable.NAME,true,                      CityForecastTable.ID to INTEGER + PRIMARY_KEY,//关键字                      CityForecastTable.CITY to TEXT,                      CityForecastTable.COUNTRY to TEXT)              db.createTable(DayForecastTable.NAME,true,                      DayForecastTable.ID to INTEGER + PRIMARY_KEY + AUTOINCREMENT,//关键字,主键                      DayForecastTable.DATE to INTEGER,                      DayForecastTable.DESCRIPTION to TEXT,                      DayForecastTable.HIGH to INTEGER,                      DayForecastTable.LOW to INTEGER,                      DayForecastTable.ICON_URL to TEXT,                      DayForecastTable.CITY_ID to INTEGER)          }          /**              我们有一个相似的函数用于删除表。              onUpgrade将只是删除表,然后重建它们。              我们只是把我们数据库作为一个缓存,所以这是一个简单安全的方法保证我们的表会如我们所期望的那样被重建。              如果我有很重要的数据需要保留,我们就需要优化onUpgrade的代码,让它根据数据库版本来做相应的数据转移。          */          override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {              db.dropTable(CityForecastTable.NAME, true)              db.dropTable(DayForecastTable.NAME, true)              onCreate(db)          }           }           介绍:             1)SqlType的特殊类型          Anko中有一种叫做SqlType的特殊类型,它可以与SqlTypeModifiers混合,比如PRIMARY_KEY。          +操作符像之前那样被重写了。          这个plus函数会把两者通过合适的方式结合起来,然后返回一个新的SqlType:          fun SqlType.plus(m: SqlTypeModifier) : SqlType {                  return SqlTypeImpl(name, if (modifier == null) m.toString()                                              else "$modifier $m")          }           2)to的函数          Kotlin标准库中包含了一个叫to的函数,作为第一参数的扩展函数,接收另外一个对象作为参数,把两者组装并返回一个Pair:          public fun "<"A, B> A.to(that: B): Pair"<"A, B> = Pair(this, that)

26.1 从数据库中保存或查询数据

  1)创建数据库存储是使用的modle类,使用映射功能          class  CityForecast(val map :

MutableMap”“<”“String,Any?>,val dailyForecast: List”<”DayForecast>){
var _id : Long by map
var city : String by map
var country : String by map
/**逻辑:
(1)这个类的实际构造参数是定义时候的===(val map : MutableMap”“<”“String,Any?>,val dailyForecast: List”<”DayForecast>)

          (2)在constructor(){}中,将一些没有封装到map中的数据,进行封装,然后返回定义时候的构造参数【解释的稀里糊涂,就是那个意思】          我们传入一个空的map,但是又一次,多亏了委托,当我们设置值到属性的时候,它会自动增加所有的值到map中。          */          constructor(id : Long,city : String,country : String ,dailyForecast: List"<"DayForecast>)                  :this(HashMap(),dailyForecast){              this._id = id              this.city = city              this.country = country          }           }           (2)use函数【ManagedSQLiteOpenHelper类的,可以用来作为处理返回结果】          forecastDbHelper.use { /**这里面直接使用forecastDbHelper的方法,不用return字段,结果直接使用 .let{}返回*/}      (3)(parser :(Map"<"String,Any?>) -> T)这是怎么定义的???      (4)kotlin的对于判断空的简写          if (city != null) dataMapper.convertToDomain(city) else null          等同于          city?.let { dataMapper.convertToDomain(it) }      (5)在toVarargArray函数结果前面使用*表示这个array会被分解成为一个vararg参数          *map.toVarargArray()                  (6)数据库insert发法        /*          * insert是一个Anko函数,它需要一个表名和一个vararg修饰的Pair"<"String, Any>作为参数。        * 这个函数会把vararg转换成Android SDK需要的ContentValues对象。map的key、value会映射到表中         * */        /*        * 在toVarargArray函数结果前面使用*表示这个array会被分解成为一个vararg参数        * */        insert(CityForecastTable.NAME, *map.toVarargArray())

27.集合和函数操作符

Iterable:父类。所有我们可以遍历一系列的都是实现这个接口。
MutableIterable:一个支持遍历的同时可以执行删除的Iterables。
Collection:这个类相是一个范性集合。我们通过函数访问可以返回集合的size、是否为空、是否包含一个或者一些item。这个集合的所有方法提供查询,因为connections是不可修改的。
MutableCollection:一个支持增加和删除item的Collection。它提供了额外的函数,比如add
、remove、clear等等。
List:可能是最流行的集合类型。它是一个范性有序的集合。因为它的有序,我们可以使用get函数通过position来访问。
MutableList:一个支持增加和删除item的List。 Set:一个无序并不支持重复item的集合。
MutableSet:一个支持增加和删除item的Set。
Map:一个key-value对的collection。key在map中是唯一的,也就是说不能有两对key是一样的键值对存在于一个map中。
MutableMap:一个支持增加和删除item的map。

    val list = listOf(1, 2, 3, 4, 5, 6)    操作符:        1--15 :总数操作符        (1)any:如果至少有一个元素符合给出的判断条件,则返回true。                list.any{ it % 2 ==0}        (2)all:如果全部的元素符合给出的判断条件,则返回true。                list.all { it "<" 10 }        (3)count:返回符合给出判断条件的元素总数。                 list.count { it % 2 == 0 }        (4)fold:在一个初始值的基础上从第一项到最后一项通过一个函数累计所有的元素                list.fold(4){total,next -> total + nex}        (5)foldRight:与fold一样,但是顺序是从最后一项到第一项。                list.foldRight(4) { total, next -> total + next }        (6)forEach:遍历所有元素,并执行给定的操作。                list.forEach{ println(it)}        (7)forEachIndexed:与forEach,但是我们同时可以得到元素的index。                list.forEachIndexed{ index,value ->println("position $index contains a $value")}        (8)max:返回最大的一项,如果没有则返回null。                list.max()        (9)maxBy :根据给定的函数返回最大的一项,如果没有则返回null。                list.maxBy { -it }        (10)min: 返回最小的一项,如果没有则返回null。                list.min()        (11)minBy:根据给定的函数返回最小的一项,如果没有则返回null。、                    list.minBy { -it }        (12)none:如果没有任何元素与给定的函数匹配,则返回true。                list.none { it % 7 == 0 }        (13)reduce:与fold一样,但是没有一个初始值。通过一个函数从第一项到最后一项进行累计。                list.reduce { total, next -> total + next }        (14)reduceRight:与reduce一样,但是顺序是从最后一项到第一项。                reduceRight { total, next -> total + next }        (15)sumBy:返回所有每一项通过函数转换之后的数据的总和。                list.sumBy { it % 2 }        16--25  过滤操作符        (16)drop :返回包含去掉前n个元素的所有元素的列表                list.drop(4)        (17)dropWhile: 返回根据给定函数从第一项开始去掉指定元素的列表。                list.dropWhile { it "<" 3 }        (18)dropLastWhile : 返回根据给定函数从最后一项开始去掉指定元素的列表。                list.dropLastWhile { it > 4 }        (19)filter: 过滤所有符合给定函数条件的元素。                list .filter { it % 2 == 0 }        (20)filterNot:过滤所有不符合给定函数条件的元素。                list.filterNot { it % 2 == 0 }        (21)filterNotNull :过滤所有元素中不是null的元素。                list.filterNotNull()        (22)slice:过滤一个list中指定index的元素。                    list.slice(listOf(1, 3, 4))        (23)take:返回从第一个开始的n个元素。                list.take(n)        (24)takeLast:返回从最后一个开始的n个元素                list.takeLast(2)        (25)takeWhile: 返回从第一个开始符合给定函数条件的元素。返回一个List集合                 list.takeWhile { it "<" 3 }        26--30 :映射操作符        (26)flatMap :遍历所有的元素,为每一个创建一个集合,最后把所有的集合放在一个集合中。                list.flatMap { listOf(it, it + 1) })        (27)groupBy:返回一个根据给定函数分组后的map。                mapOf("odd" to listOf(1, 3, 5), "even" to listOf(2, 4, 6)), list.groupBy { if (it % 2 == 0) "even" else "odd" }        (28)map :返回一个根据给定函数分组后的map。                list.map { it * 2 }        (29)mapIndexed : 返回一个每一个元素根据给定的包含元素index的函数转换所组成的List。                list.mapIndexed { index, it -> index * it }        (30)mapNotNull : 返回一个每一个非null元素根据给定的函数转换所组成的List。                 listWithNull.mapNotNull { it * 2 }        31--42 :元素操作符        (31)contains :如果指定元素可以在集合中找到,则返回true。                 list.contains(2)        (32)elementAt:返回给定index对应的元素,如果index数组越界则会抛出IndexOutOfBoundsException                list.elementAt(1)        (33)elementAtOrElse:返回给定index对应的元素,如果index数组越界则会根据给定函数返回默认值。                list.elementAtOrElse(10, { 2 * it })        (34)elementAtOrNull :返回给定index对应的元素,如果index数组越界则会返回null。                list.elementAtOrNull(10)        (35)first: 返回符合给定函数条件的第一个元素。                list.first { it % 2 == 0 }        (36)firstOrNull:返回符合给定函数条件的第一个元素,如果没有符合则返回null。                list.firstOrNull { it % 7 == 0 }        (37)indexOf:返回指定元素的第一个index,如果不存在,则返回-1                list.indexOf(4)        (38)indexOfFirst:返回第一个符合给定函数条件的元素的index,如果没有符合则返回-1。                list.indexOfFirst { it % 2 == 0 }        (39)indexOfLast:返回最后一个符合给定函数条件的元素的index,如果没有符合则返回-1。                list.indexOfLast { it % 2 == 0 }        (40)last:返回符合给定函数条件的最后一个元素。 ----lastIndexOf,lastOrNull        (41)single:返回符合给定函数的单个元素,如果没有符合或者超过一个,则抛出异常                list.single { it % 5 == 0 }        (42)singleOrNull:返回符合给定函数的单个元素,如果没有符合或者超过一个,则返回null。                list.singleOrNull { it % 7 == 0 }        43--47 :生产操作符        (43)merge:把两个集合合并成一个新的,相同index的元素通过给定的函数进行合并成新的元素作为新的集合的一个元素,返回这个新的集合。新的集合的大小由最小的那个集合大小决定。                val list = listOf(1, 2, 3, 4, 5, 6)                val listRepeated = listOf(2, 2, 3, 4, 5, 5, 6)                list.merge(listRepeated) { it1, it2 -> it1 + it2 }        (44)partition:把一个给定的集合分割成两个,第一个集合是由原集合每一项元素匹配给定函数条件返回true的元素组成,第二个集合是由原集合每一项元素匹配给定函数条件返回false的元素组成。                assertEquals(                        Pair(listOf(2, 4, 6), listOf(1, 3, 5)),                         list.partition { it % 2 == 0 }                    )        (45)plus:返回一个包含原集合和给定集合中所有元素的集合,因为函数的名字原因,我们可以使用+操作符。                list + listOf(7, 8)        (46)zip:返回由pair组成的List,每个pair由两个集合中相同index的元素组成。这个返回的List的大小由最小的那个集合决定。                assertEquals(                    listOf(Pair(1, 7), Pair(2, 8)),                     list.zip(listOf(7, 8))                )        (47)unzip:从包含pair的List中生成包含List的Pair。                assertEquals(                    Pair(listOf(5, 6), listOf(7, 8)),                     listOf(Pair(5, 7), Pair(6, 8)).unzip()                )        48--52 : 顺序操作符        (48)reverse:返回一个与指定list相反顺序的list。                list.reverse()        (49)sort:返回一个自然排序后的list【按大小排序】                list.sort()        (50)sortBy:返回一个根据指定函数排序后的list。                list.sortBy { it % 3 }        (51)sortDescending:返回一个降序排序后的List。                list.sortDescending()        (52)sortDescendingBy:返回一个根据指定函数降序排序后的list。                list.sortDescendingBy { it % 3 }

28.函数后面返回的时候,添加一个?,表示返回可为null

fun requestDayForecast(id: Long): Forecast?

29.可null类型,Kotlin中一切都是对象(甚至是Java中原始数据类型),一切都是可null的
指定一个变量是可null是通过在类型的最后增加一个问号
val a: Int? = null
// ?.()–?:()

        val myString = a?.toString() ?: "" //这里我们使用了安全访问操作符(?)。只有这个变量不是null的时候才会去执行前面的那行代码。否则,它不会做任何事情。并且我们甚至可以使用Elvis operator(?:):        val myString = a?.toString() ?: throw IllegalStateException()        //!!.        a!!.toString() //我们确定我们是在用一个非null变量,但是他的类型却是可null的。我们可以使用!!操作符来强制编译器执行可null类型时跳过限制检查:

30.方法定义的解释
(1)
private fun “<”T : Any> requestToSources (f : (ForecastDataSource) -> T?) : T = sources.firstResult{f(it)}
(2)
inline fun “”<”“T,R : Any> Iterable”<”T>.firstResult(predicate: (T) -> R?) : R{
for (element in this){
val result = predicate(element)
if(result!=null) return result
}
throw NoSuchElementException(“No element matching predicate was found.”)
}

        解释:        1)requestToSources 是方法名         2) (f : (ForecastDataSource) -> T?)  说明,在自定义方法requestToSources之后,我们可以跟着{},而 f 就是{}里面的方法体,并且返回一个 T 类型的数据[ -> T?]        同理        firstResult是Iterable的扩展函数,predicate是{}里面的方法体,可以定义成任何方法名,比如 a,b,c;这个方法体中接收的数据类型是T【predicate: (T) -> R?】转化成R?    31--34 Ranges        Range表达式使用一个..操作符,它是被定义实现了一个RangTo方法。

31. if 表达式

        if表达式总是返回一个value。如果一个分支返回了Unit,那整个表达式也将返回Unit,它是可以被忽略的,这种情况下它的用法也就跟一般Java中的if条件一样了。            (1)返回一个value            val res = if (x != null && x.size() >= days) x else null            (2)返回Unit,等同于Java中的if            if(x>0){                toast("x is greater than 0")            }else if(x==0){                 toast("x equals 0")            }else{                toast("x is smaller than 0")            }

32.When表达式

        when表达式与Java中的switch/case类似,但是要强大得多。这个表达式会去试图匹配所有可能的分支直到找到满意的一项。然后它会运行右边的表达式。与Java的switch/case不同之处是参数可以是任何类型,并且分支也可以是一个条件        (1)对于默认的选项,我们可以增加一个else分支,它会在前面没有任何条件匹配时再执行。条件匹配成功后执行的代码也可以是代码块:            [else相当于finally]                when (x){                    1 -> print("x == 1")                     2 -> print("x == 2")                     else -> {                        print("I'm a block")                        print("x is neither 1 nor 2")                    }                }        (2)因为它是一个表达式,它也可以返回一个值。我们需要考虑什么时候作为一个表达式使用,它必须要覆盖所有分支的可能性或者实现else分支。否则它不会被编译成功:            条件可以是一系列被逗号分割的值:            [相当于case的贯穿]                val result = when (x) {                    0, 1 -> "binary"                    else -> "error"                }            可以检测参数类型并进行判断:再条件右边的代码中,参数会被自动转型,所以你不需要去明确地做类型转换                when(view) {                    is TextView -> view.setText("I'm a TextView")                    is EditText -> toast("EditText value: ${view.getText()}")                    is ViewGroup -> toast("Number of children: ${view.getChildCount()} ")                    else -> view.visibility = View.GONE                }            它还让检测参数否在一个数组范围甚至是集合范围成为可能:                val cost = when(x) {                    in 1..10 -> "cheap"                    in 10..100 -> "regular"                    in 100..1000 -> "expensive"                    in specialValues -> "special value!"                    else -> "not rated"                }            甚至可以从对参数做需要的几乎疯狂的检查摆脱出来。它可以使用简单的if/else链替代:【*******】                valres=when{                    x in 1..10 -> "cheap"                    s.contains("hello") -> "it's a welcome!"                    v is ViewGroup -> "child count: ${v.getChildCount()}"                    else -> ""                }

33.For循环

        (1)简单的遍历        for (item in collection) {            print(item)        }        (2)如果你需要更多使用index的典型的迭代,我们也可以使用ranges:        【重点:0..viewGroup.getChildCount() - 1:::两个点】        for (index in 0..viewGroup.getChildCount() - 1) {            val view = viewGroup.getChildAt(index)            view.visibility = View.VISIBLE        }    (3)在我们迭代一个array或者list,一系列的index可以用来获取到指定的对象,所以上面的方式不是必要的:        for (i in array.indices)             print(array[i])    (4)可以使用downTo函数        for(i in 10 downTo 0)            println(i)        for (i in 1..4 step 2) println(i)        for (i in 4 downTo 1 step 2) println(i)    (5)如果你想去创建一个open range(不包含最后一项,译者注:类似数学中的开区间),你可以使用until函数:        【这一行会打印从0到3,但是会跳过最后一个值。这也就是说0 until 4 == 0..3。在一个list中迭代时,使用(i in 0 until list.size)比(i in 0..list.size - 1)更加容易理解。】        for (i in 0 until 4) println(i)

34.While和do/while循环【与Java一样】

(1)
while(x > 0){
x–
}
(2)
do{
val y = retrieveData()
} while (y != null) // y在这里是可见的!

35.try和throw是表达式

        在Kotlin中,几乎一切都是表达式,也就是说一切都会返回一个值。这在函数式编程中是非常重要的,当你使用try-catch处理边界的问题或者当抛出异常的时候。        比如,在上一个例子中,我们可以给结果分配一个exception就算他们不是相同的类型,而不是必须要去创建一个完整的代码块。        当我们需要在一个when分支中抛出一个exception的时候也是非常有用:         val x = when(y){             in 0..10 -> 1            in 11..20 -> 2            else -> throw Exception("Invalid")        }        try-catch中也是一样,我们可以根据try的结果分配一个值:         val x = try{ doSomething() }catch{ null }

36.启动一个activity:reified函数

startActivity”<”DetailActivity>(DetailActivity.ID to it.id,
DetailActivity.CITY_NAME to result.city)

37.接口

当两个类继承自一个接口,非常典型的是它们两者共享相同的实现。但是Java 7中的接口只能定义行为,但是不能去实现它。
Kotlin接口在某一方面它可以实现函数。它们与类唯一的不同之处是它们是无状态(stateless)的,所以属性需要子类去重写。类需要去负责保存接口属性的状态。

      JAVA:          interface FlyingAnimal {              fun fly()          }              class Bird : FlyingAnimal {                  val wings: Wings = Wings()                  override fun fly() = wings.move()              }              class Bat : FlyingAnimal {                  val wings: Wings = Wings()                  override fun fly() = wings.move()              }                  kotlin:      interface FlyingAnimal {          val wings: Wings          fun fly() = wings.move()            }          class Bird : FlyingAnimal {              override val wings: Wings = Wings()          }          class Bat : FlyingAnimal {              override val wings: Wings = Wings()          }

38.委托

委托模式是一个很有用的模式,它可以用来从类中抽取出主要负责的部分。委托模式是Kotlin原生支持的,所以它避免了我们需要去调用委托对象。委托者只需要指定实现的接口的实例。

      interface CanFly {          fun fly()           }          class AnimalWithWings : CanFly {              val wings: Wings = Wings()              override fun fly() = wings.move()          }      //我们可以使用接口来指示鸟可以飞行,但是鸟的飞行方式被定义在一个委托中,这个委托定义在构造函数中,所以我们可以针对不同的鸟使用不同的飞行方式。动物使用翅膀飞行的方式被定义在另一个类中      class Bird(f: CanFly) : CanFly by f      val birdWithWings = Bird(AnimalWithWings())  birdWithWings.fly()      class Bat : CanFly by AnimalWithWings()

39.泛型例子

(1)let函数 解释: let实在是一个简单的函数,它可以被任何对象调用。
它接收一个函数(接收一个对象,返回函数结果)作为参数,作为参数的函数返回的结果作为整个函数的返回值。
它在处理可null对象的时候是非常有用的,下面是它的定义:

                  inline fun "<"T, R> T.let(f: (T) -> R): R = f(this)                  它使用了两个泛型类型:T 和 R。第一个是被调用者定义的,它的类型被函数接收到。第二个是函数的返回值类型。              if (forecast != null) dataMapper.convertDayToDomain(forecast) else null              这代码是非常丑陋的,我们不需要使用这种方式去处理可null对象。实际上如果我们使用let,都不需要if:              forecast?.let { dataMapper.convertDayToDomain(it) }              多亏?.操作符,let函数只会在forecast不是null的时候才会执行。否则它会返回null。也就是我们想达到的效果。                      (2)with函数          with接收一个对象和一个函数,这个函数会作为这个对象的扩展函数执行。这表示我们根据推断可以在函数内使用this。          inline fun "<"T, R> with(receiver: T, f: T.() -> R): R = receiver.f()          型在这里也是以相同的方式运行:T代表接收类型,R代表结果。如你所见,函数通过f: T.() -> R声明被定义成了扩展函数。这就是为什么我们可以调用receiver.f()。      (3)apply函数          它看起来于with很相似,但是是有点不同之处。apply可以避免创建builder的方式来使用,因为对象调用的函数可以根据自己的需要来初始化自己,然后apply函数会返回它同一个对象:          inline fun "<"T> T.apply(f: T.() -> Unit): T { f(); return this }          这里我们只需要一个泛型类型,因为调用这个函数的对象也就是这个函数返回的对象。一个不错的例子:          val textView = TextView(context).apply {              text = "Hello"              hint = "Hint"              textColor = android.R.color.white          }

40.内部类

访问外部类的成员,我们需要用inner声明这个类: class Outer {
private val bar: Int = 1
inner class Inner{
fun foo() = bar
} }

      val demo = Outer().Inner().foo() // == 1

41.枚举

enum class Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY,
FRIDAY, SATURDAY } 枚举可以带有参数: enum class Icon(val res: Int) {
UP(R.drawable.ic_up), SEARCH(R.drawable.ic_search),
CAST(R.drawable.ic_cast) }

  val searchIconRes = Icon.SEARCH.res  枚举可以通过String匹配名字来获取,我。      val search: Icon = Icon.valueOf("SEARCH")  们也可以获取包含所有枚举的Array,所以我们可以遍历它        val iconList: Array"<"Icon> =

Icon.values()

  每一个枚举都有一些函数来获取它的名字、声明的位置:       val searchName: String =

Icon.SEARCH.name() val searchPosition: Int = Icon.SEARCH.ordinal()

原创粉丝点击