START
ABCDEFGHIJKLMNOPQRSTUVWXYZ
END
复制代码
若是不考虑kotlin的特性直接写成java风格的代码以下java
fun alphabet(): String {
val result = StringBuilder()
result.append("START\n")
for (letter in 'A'..'Z') {
result.append(letter)
}
result.append("\nEND")
return result.toString()
}
复制代码
可使用with简化代码android
fun alphabet3(): String {
return with(StringBuilder()) {
append("START\n")
for (letter in 'A'..'Z') {
this.append(letter)
}
append("\nEND")
toString()
}
}
复制代码
with函数内部经过this来访问传入的参数,这里具体指的是StringBuilder()的结果,with的返回值就是花括号的最后一行,也就是StringBuilder.toString()ios
另外with里面的this能够省去bash
fun alphabet4() =
with(StringBuilder()) {
append("START\n")
for (letter in 'A'..'Z') {
this.append(letter)
}
append("\nEND")
toString()
}
复制代码
有一个对象app
class User {
var firstName = ""
var lastName = ""
var age = 10
var address = "SH"
}
复制代码
如今要对其初始化,能够像java那样ide
var user2 = User()
user2.firstName = "chen"
user2.lastName = "si"
user2.age = 30
user2.address = "BJ"
复制代码
kotlin中为咱们提供了apply方法,方便一系列的初始化函数
var user = User().apply {
firstName = "chen"
lastName = "si"
age = 30
address = "BJ"
}
复制代码
对一个TextView初始化就变成了这样post
textView.apply {
text = "hello"
textSize = 32f
textAlignment = TEXT_ALIGNMENT_CENTER
}
复制代码
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
复制代码
经过with的函数声明能够看出来,with接受两个参数,而且在第二个参数里面能够直接访问第一个参数的方法,with的返回值是第二个参数,也就是第二个代码块最后一行ui
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
复制代码
apply函数是个扩展函数,接受一个参数,返回值就是参数自身。this
val (red, green, blue) = Color.RED
val (left, top, right, bottom) = Rect(10, 20, 30, 40)
val (x, y) = Point(10, 20)
复制代码
fun <T> joinToString(collection: Collection<T>, separator: String, prefix: String, postfix: String): String {
val result = StringBuilder(prefix)
for ((index, element) in collection.withIndex()) {
if (index > 0) result.append(separator)
result.append(element)
}
result.append(postfix)
return result.toString()
}
val list = listOf("one", "two", "three", "four", "five")
// 不标明参数名
println(joinToString(list, " - ", "[", "]"))
复制代码
这段代码把list按顺序输出,最前面加上"[" ,中间加上" - ",最后加上"]",输出结果为
[one - two - three - four - five]
复制代码
这样写的问题在于要传递过多参数,固然能够像java那样提供多个重载版原本实现默认参数的目的,kotlin中直接提供了默认参数的语法
fun <T> joinToString2(collection: Collection<T>, separator: String = ", ", prefix: String = "", postfix: String = ""): String {
val result = StringBuilder(prefix)
for ((index, element) in collection.withIndex()) {
if (index > 0) result.append(separator)
result.append(element)
}
result.append(postfix)
return result.toString()
}
println(joinToString2(list, " - "))
println(joinToString2(list, " , ", "["))
复制代码
输出为
[one - two - three - four - five]
one - two - three - four - five
复制代码
joinToString2(list, " - ")
指定了separator的值为 " - ",其余没有指定的均使用默认值。
joinToString2(list, " , ", "[")
指定了separator和prefix,而postfix使用默认值。
另外可使用扩展函数进一步简化代码
fun <T> Collection<T>.joinToString3(separator: String = ", ", prefix: String = "", postfix: String = ""): String {
val result = StringBuilder(prefix)
for ((index, element) in withIndex()) {
if (index > 0) result.append(separator)
result.append(element)
}
result.append(postfix)
return result.toString()
}
println(list.joinToString3("/"))
复制代码
有个默认参数以后能够大大简化安卓中自定义view中构造函数
class MyLinearLayout2 constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr)
复制代码
class Point(val x: Int, val y: Int) {
operator fun plus(other: Point): Point {
return Point(x + other.x, y + other.y)
}
override fun toString(): String {
return "Point(x=$x, y=$y)"
}
}
复制代码
重写plus方法,前面加上operator关键字, 而后在函数里面定义具体的实现,以后就可使用 加好直接操做对象了。
val point1 = Point(10, 10)
val point2 = Point(4, 4)
val point3 = point1 + point2
复制代码
再看个示例:
val spanString = "Copyright".toSpannable()
spanString.setSpan(StyleSpan(BOLD), 0, spanString.length, SPAN_INCLUSIVE_EXCLUSIVE)
spanString.setSpan(UnderlineSpan(), 0, spanString.length, SPAN_INCLUSIVE_EXCLUSIVE)
spanString.setSpan(StyleSpan(Typeface.ITALIC), 0, spanString.length, SPAN_INCLUSIVE_EXCLUSIVE)
textView.setText(spanString)
复制代码
这段代码 给TextView的上显示的文字一次加上 加粗,下划线以及斜体的效果 借助运算符重载和ktx这段代码也能够简化
val spannable = "Eureka!!!!".toSpannable()
spannable += StyleSpan(BOLD) // Make the text bold with +=
spannable += UnderlineSpan() // Make the text underline with +=
spannable += StyleSpan(ITALIC)
textView.setText(spanString)
复制代码
点击事件通常这么写
button.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
handleClick(v)
}
})
复制代码
有了lambda以后能够这么写
button.setOnClickListener({ v ->
{
handleClick(v)
}
})
复制代码
参数v能够去掉,直接使用it代替
button.setOnClickListener({
handleClick(it)
})
复制代码
若是最后一个参数是高阶函数,能够直接移出小括号里面
button.setOnClickListener() {
handleClick(it)
}
复制代码
若是只有一个参数,而且这个参数是高阶函数,能够把小括号移除
button.setOnClickListener {
handleClick(it)
}
复制代码
看一下前面的一个扩展函数
fun <T> Collection<T>.joinToString3(separator: String = ", ", prefix: String = "", postfix: String = ""): String {
val result = StringBuilder(prefix)
for ((index, element) in withIndex()) {
if (index > 0) result.append(separator)
result.append(element)
}
result.append(postfix)
return result.toString()
}
复制代码
这个函数的问题在于扩展性较差,目前只能把element的toString的结果加到最终的输出,若是想留出本身实现该怎么办呢? 这时候就须要高阶函数出场了
/扩展函数
fun <T> Collection<T>.joinToString(separator: String = " ,", prefix: String = " ", postfix: String = " ", transform: (T) -> String = { it.toString() }): String {
val result = StringBuilder(prefix)
for ((index, element) in this.withIndex()) {
if (index > 0) result.append(separator)
result.append(transform(element))
}
result.append(postfix)
return result.toString()
}
var listOf = listOf("Chen", "Rui", "Feng")
println(listOf.joinToString())
println(listOf.joinToString { it.toLowerCase() })
println(listOf.joinToString(transform = { it.toUpperCase() }))
复制代码
Chen ,Rui ,Feng
chen ,rui ,feng
CHEN ,RUI ,FENG
复制代码
经过高阶函数能够把本身须要的输出方式传递进去
再看个例子
data class SiteVisit(val path: String,
val duration: Double,
val os: OS)
enum class OS { WINDOWS, LINUX, MAC, IOS, ANDROID }
val log = listOf(
SiteVisit("/", 34.0, OS.WINDOWS),
SiteVisit("/", 22.0, OS.MAC),
SiteVisit("/login", 12.0, OS.WINDOWS),
SiteVisit("/signup", 8.0, OS.IOS),
SiteVisit("/", 16.3, OS.ANDROID)
)
复制代码
定义一个类SiteVisit
有三个参数,分别表示用户访问的路径,访问持续时间以及用户的操做系统
如今要统计出操做系统是WINDOWS
的用户的平均访问时间
log.filter { it.os == OS.WINDOWS }
.map { it.duration }
.average()
复制代码
要统计出操做系统是MAC
的用户的平均访问时间
log.filter { it.os == OS.MAC }
.map { it.duration }
.average()
复制代码
若是统计IOS
用户的平均访问时间呢?再写一遍? 能够抽取出一个函数出来
fun List<SiteVisit>.averageDurationFor(os: OS) =
filter { os == it.os }
.map { it.duration }
.average()
复制代码
调用的时候直接传入操做系统类型就行
log.averageDurationFor(OS.WINDOWS)
log.averageDurationFor(OS.MAC)
复制代码
如今问题来了,
WINDOWS
和MAC
用户的平均访问时间IOS
用户访问/login
页面的平均访问时间刚刚的函数就没办法使用了,这时候就须要高阶函数了
fun List<SiteVisit>.averageDurationFor2(predicate: (SiteVisit) -> Boolean) =
filter { predicate(it) }
.map { it.duration }
.average()
复制代码
调用的时候直接把条件传进去
//android and ios average time
println(log.averageDurationFor2 { it.os == OS.ANDROID || it.os == OS.IOS })
//ios & login page average time
println(log.averageDurationFor2 { it.os == OS.WINDOWS && it.path == "/login" })
复制代码
有了这个高阶函数 最开始统计出操做系统是MAC
的用户的平均访问时间的代码能够写成这样子
log.averageDurationFor2 { it.os == OS.MAC })
复制代码
参考文档:
Kotlin in action