Pair
val equipment = "fishent" to "catching fish"
println(equipment.first)
//output
fishnet
val equipment = "fishent" to "catching fish" to "of big size" to "and strong"
println(equipment)
//output
(((fishnet, catching fish), of big size), and strong)
println(equipment.first)
//output
((fishnet, catching fish), of big size)
println(equipment.first.first)
//output
(fishnet, catching fisht)
val equip = ("fishnet" to "catching fish" to ("of big size" to "and strong"))
val fishnet = "fishent" to "catching fish"
val (tool, use) = fishnet
println("The $tool is a tool for $use")
//output
The fishnet is a tool for catching fish
val fishnetString = fishnet.toString()
println(fishnetString)
//output
(fishnet, catching fish)
println(fishnet.toList())
//output
[fishnet, catching fish]
fun giveMeATool(): Pair<String, String>{
return ("fishnet" to "catching")
}
val (tool, use) = giveMeATool()
println(tool)
//output
fishnemt
println(use)
//output
catching
Collections
listOf(): cannot change
-
listOf().toReverse()不会修改原来的list,而是重新创建一个新的list -
listOf(1,3,5).sum():等于9 -
如果是不知道要怎么做sum的参数可以用
sumBy: takes a lambda that specifies what property of the elements to summarizelistOf("a","b","cc").sumBy {it.length}等于 4
mutableListOf(): can change
val symptoms = mutableListOf("white spots", "red spots", "not eating", "bloated", "belly up")
symptoms.add()
symptoms.remove()
symptoms.contains("red") //false
symptoms.comtains("red spots") //true
// subList(firstArguments, endExcludingIndex )
println(symptoms.subList(4, symptoms.size)) // [belly up]
mapping
val cures = mapOf("white spots" to "Ich", "red sores" to "hole disease")
println(cures.get("white spots))
println(cures["white spots"])
getOrDefault: 如果我们map的东西没有值,找不到,还可以给一个default value:即 cures里找不到bloated → 那么就会返回一个默认值"sorry I don't know"
println(cures.getOrDefault("bloated", "sorry I don't know"))
- 如果不只想要一个返回值的话,还可以用
getOrElse花括号内的语句是可以被执行的,可以用来比如返回一个网页等等
cures.getOrElse("bloated:) { "No cure for this" }
mutableMapOf(): use to put & remove items
val inventory = mutableMapOf("fishnet" to 1)
inventory.put("tank scrubber", 3)
inventory.remove("fishnet", 1)
listOf() & mapOf() make immutable collections: can add & remove → 多用于线程中,以免很多的线程都需要接触这个collection
mutableListOf() & mutableMapOf() make mutable collections: can modify
Constants
区别在于 const val的值是在编译的时候才确定的,但是val是在程序执行的时候assign和确定的
val num = 3
const val num = 5
val number = getNumberFun()
const val cantGetNumber = getNumberFun() // 这样是不可以的,因为const val 是在编译的时候就要分配值,等不到这个函数运行完返回值
const val:
-
const 只允许在top-level级别和object中声明
- top-level就是位于代码文件的最外部,比如常见的类(非内部类和嵌套类)就是在top-level。意思是在结构上常量不属于任何的类,而是属于文件
- object中可以指的是最外部的object也可以指的是
companion object.
-
必须修饰val
-
const val 可见性为
public final static,可以直接访问。val 可见性为
private final static,并且val 会生成方法getNormalObject(),通过方法调用访问。当定义常量时,出于效率考虑,我们应该使用const val方式,避免频繁函数调用。
companion object: initialized from the static constructor of the containing class → 在对象创建的时候创建
plain object: are initialized lazily on the first access to that object → 即 第一次使用的时候
object Constants{
const val CONSTANT1 = "object constant"
}
val foo = Constants.CONSTANT1
class MyClass {
//因为没有一个top level的class, 所有要在class里面用 const的话就要用companion object给包起来
//而 companion object的特点就是在对象初次创建的时候就给创建,即编译的时候就能确定值
//但普通的object是在第一次使用的时候才赋值,即运行的时候再赋值,所以在class里面,要用companion obj
companion object {
const val CONSTANT2 = "constant inside companion"
}
}
Extension Function
作用:add function到已有的一个class,但是不需要访问其内部的代码
fun String.hasSpaces() : Boolean {
val found = this.find{it == ' '}
return found != null
}
fun extensionExample() {
"Does it has spaces".hasSpaces() // true
}
简化一下:
fun String.hasSpaces() = find { it==' ' } != null
fun extensionExample() {
"Does it has spaces".hasSpaces() // true
}
很适合用在给不属于自己的class添加功能 / 函数
class AquariumPlant(val color: String, private size:Int)
fun AquariumPlant.isRed() = color == "Red" //通常可以用来作为 helper function
//会报错,因为extension class只能访问public variable, 不能访问私有的
//就像一开始说得,extension fun是不会去访问内部代码的
fun AquariumPlant.isBig() = size > 50
extension function resolved statically → 在编译的时候就确定了,
下面的例子中,AquariumPlant的print()函数在定义的时候就已经决定了输出 "Aquarium Plant",然后在编译阶段就确定了这个值,所以后面是不会再变了。因而,即使 aquariumPlant实际是等于 plant : GreenAquariumPlant的,也不会输出"Green Aquarium plant"
open class AquariumPlant(val color:String, private val size : Int)
class GreenAquariumPlant(size:Int) : AquariumPlant("Green", size)
fun AquariumPlant.print() = println("Aquarium Plant")
fun GreenAquariumPlant.print() = println("Green Aquarium plant")
fun staticExample() {
val plant = GreenAquariumPlant(size = 50)
plant.print() // Green Aquarium plant
val aquariumPlant : AquariumPlant = plant
plant.print() // Aquarium Plant
}
Extension Properties
Similarly to functions, Kotlin supports extension properties:
val AquariumPlant.isGreen:Boolean
get() = color == "Green"
fun propertyExample(){
val plant = AquariumPlant("Green", 50)
plant.isGreen //true
}
Note that, since extensions do not actually insert members into classes, there's no efficient way for an extension property to have a backing field. This is why initializers are not allowed for extension properties.即 extension property 不能直接初始化。 Their behavior can only be defined by explicitly providing getters/setters.
Example:
val AquariumPlant.isGreen:Boolean = color == "Green" // error: initializers are not allowed for extension properties
val House.number = 1 // error: initializers are not allowed for extension properties
Nullable receiver
Note that extensions can be defined with a nullable receiver type. Such extensions can be called on an object variable even if its value is null, and can check for this == null inside the body. This is what allows you to call toString() in Kotlin without checking for null: the check happens inside the extension function.
fun Any?.toString(): String {
if (this == null) return "null"
// after the null check, 'this' is autocast to a non-null type, so the toString() below
// resolves to the member function of the Any class
return toString()
}
fun AquariumPlant?.pull() {
this?.apply{
println("removing $this") //即 this 可以为null
}
}
fun nullableExample() {
val plant : AquariumPlant? = null
plant.pull() //可以成功运行的,不是错的。 可以接受空
}
Companion Object Extensions
class MyClass {
companion object { } // will be called "Companion"
}
fun MyClass.Companion.printCompanion() { println("companion") }
fun main() {
MyClass.printCompanion()
}
Generic Class
作用:
generic class可以让一个class变成一个通用的class, 不受参数类型所限制,例如下面的例子,其实是同样的class,就因为类型不同,就要重新写一个class,如果使用generic class 的话,就能够是一个通用型的class, 传入一个type(T),根据T来判断类型
class MyIntList {
fun get(pos: Int): Int { return 0}
fun addItem(item:Int) {}
}
class MyStringList {
fun get(pos: Int): String { return 0}
fun addItem(item: String) {}
}
class MyList<T> { // T stand for type, 但是也可以换成其他的东西,只是通常用T
fun get(pos: Int): T {return 0}
fun addItem(item : T) {}
}
fun workWithMyList() {
val intList: MyList<String>
val fishList: MyList<Fish>
}
Example
open class WaterSupply(var needsProcessed:Boolean)
class TapWater : WaterSupply(true) {
fun addChemicalCleaners() {
needsProcessed = false
}
}
class FishStoreWater : WaterSupply(false)
class LakeWater : WaterSupply(true) {
fun filter() {
needsProcessed = false
}
}
class Aquarium<T>(val waterSupply: T)
fun genericExample() {
val aquarium = Aquarium<TapWater>(TapWater()) //TapWater类型
aquarium.waterSupply.addChemicalCleaners() //不需要做另外的cast,可以直接调用TapWater这个class所拥有的方法
/*****下面这个方法也是可以的***/
val aquarium = Aquarium(TapWater()) //不用写<TapWater>,因为可以从参数的类型给推断出来是tapwater
aquarium.waterSupply.addChemicalCleaners()
}
Type 类型
如果按上面的例子,那么这个class可以是任意类型的,包括null
class Aquarium<T>(val waterSupply: T)
fun genericExample() {
val aquarium = Aquarium(String)
println(aquarium.waterSupply) // ok的
val aquarium = Aquarium(null)
aquarium.waterSupply //这样也不会报错因为T如果不加限定就可以为任何类型
}
// 所以上面的class 和 下面的class是等价的
class Aquarium<T:Any?> (val waterSuppy: T) // 即: <T> == <T:any?>
那么自然,如果不想要接受null这个类型,就要去掉 ?
class Aquarium<T : Any> (val waterSuppy: T)
fun genericExample() {
val aquarium = Aquarium(null)
//现在这个地方就会报错了, not satisfied: inferred type nothing? is no subtype of Any
aquarium.waterSupply
}
如果想再给 T一个具体的类型:
class Aquarium<T : WaterSupply> (val waterSupply: T)
fun genericExample() {
val aquarium = Aquarium(String)
//那么现在这个地方就会报错了, 因为string不是WaterSupply类型
//但是WaterTap, FishStoreWater,LakeWater 都可以,因为它们都继承了WaterSupply, 都是它的subtype
aquarium.waterSupply
}
check()和assertion()差不多:throw an illegal exception if its argument is false
class Aquarium<T : WaterSupply> (val waterSupply: T) {
fun addWater() {
check( !waterSupply.needsProcessed ){"water supply needs processed"}
println("add water from $waterSupply")
}
}
上面的check意思是,如果不需要processed, 那么就执行println()语句,不然抛出带有error message:"water supply needs processed"的异常,
fun genericExample() {
val aquarium = Aquarium(LakeWater())
aquarium.waterSupply.filter() // lakewater是需要处理的,如果没有这一条语句,直接执行下面一条语句,那么根据class中的check()语句,就会抛出异常,说 water needs processed.
aquarium.addWater()
}