Kotlin 语法基础大全,从例子着手的 从0到1的学习 --

2020-10-22  本文已影响0人  帅不过王力宏

Kotlin 语法基础大全,从例子着手的 从0到1的学习 -- 基础介绍
Kotlin 语法基础大全,从例子着手的 从0到1的学习 -- 流程控制
Kotlin 语法基础大全,从例子着手的 从0到1的学习 -- 特殊的类
Kotlin 语法基础大全,从例子着手的 从0到1的学习 -- 函数
Kotlin 语法基础大全,从例子着手的 从0到1的学习 -- 集合
Kotlin 语法基础大全,从例子着手的 从0到1的学习 -- 作用域
Kotlin 语法基础大全,从例子着手的 从0到1的学习 -- 代理
Kotlin 语法基础大全,从例子着手的 从0到1的学习 -- 产品级特性
翻译来源

hello world

package org.kotlinlang.play         // 1

fun main() {                        // 2
    println("Hello, World!")        // 3
}

在早于1.3版本main 方法必须要有参数

fun main(args: Array<String>) {
    println("Hello, World!")
}

方法

普通方法
fun printMessage(message: String): Unit {                               // 1
    println(message)
}

fun printMessageWithPrefix(message: String, prefix: String = "Info") {  // 2
    println("[$prefix] $message")
}

fun sum(x: Int, y: Int): Int {                                          // 3
    return x + y
}

fun multiply(x: Int, y: Int) = x * y                                    // 4

fun main() {
    printMessage("Hello")                                               // 5                    
    printMessageWithPrefix("Hello", "Log")                              // 6
    printMessageWithPrefix("Hello")                                     // 7
    printMessageWithPrefix(prefix = "Log", message = "Hello")           // 8
    println(sum(1, 2))                                                  // 9
}

通过tools show kotlin bytecode 再decompile 可以看到kotlin的java代码长什么样子


fun printMessageWithPrefix(message: String, prefix: String = "Info") {  // 2
    println("[$prefix] $message")
}

fun main() {
    printMessageWithPrefix("1")
    printMessageWithPrefix("1", "2")
}

kotlin代码转化之后成为的样子,·从这可以看到kotlin在这里的处理是创建一个不同名字的方法,直接改了调用的地方,不是如预想中的重载·


  public static final void printMessageWithPrefix(@NotNull String message, @NotNull String prefix) {
     Intrinsics.checkParameterIsNotNull(message, "message");
     Intrinsics.checkParameterIsNotNull(prefix, "prefix");
     String var2 = '[' + prefix + "] " + message;
     boolean var3 = false;
     System.out.println(var2);
  }

  // $FF: synthetic method
  public static void printMessageWithPrefix$default(String var0, String var1, int var2, Object var3) {
     if ((var2 & 2) != 0) {
        var1 = "Info";
     }

     printMessageWithPrefix(var0, var1);
  }

  public static final void main() {
     printMessageWithPrefix$default("1", (String)null, 2, (Object)null);
     printMessageWithPrefix("1", "2");
  }

  // $FF: synthetic method
  public static void main(String[] var0) {
     main();
  }
infix functions 中缀方法

如果成员方法和扩展方法只有一个参数那么可以转化为中缀方法

fun main() {

  infix fun Int.times(str: String) = str.repeat(this)        // 1
  println(2 times "Bye ")                                    // 2

  val pair = "Ferrari" to "Katrina"                          // 3
  println(pair)

  infix fun String.onto(other: String) = Pair(this, other)   // 4
  val myPair = "McLaren" onto "Lucas"
  println(myPair)

  val sophia = Person("Sophia")
  val claudia = Person("Claudia")
  sophia likes claudia                                       // 5
}

class Person(val name: String) {
  val likedPeople = mutableListOf<Person>()
  infix fun likes(other: Person) { likedPeople.add(other) }  // 6
}

local functions 内部方法
定义在方法中的方法

操作符方法

明确的方法可以升级为 操作符方法,允许调用者使用相应的符号进行运算

operator fun Int.times(str: String) = str.repeat(this)       // 1
println(2 * "Bye ")                                          // 2

operator fun String.get(range: IntRange) = substring(range)  // 3
val str = "Always forgive your enemies; nothing annoys them so much."
println(str[0..14])                                          //14
带有 vararg 参数的方法

vararg 就相当于 java 中 String... args

fun printAll(vararg messages: String) {                            // 1
    for (m in messages) println(m)
}
printAll("Hello", "Hallo", "Salut", "Hola", "你好")                 // 2

fun printAllWithPrefix(vararg messages: String, prefix: String) {  // 3
    for (m in messages) println(prefix + m)
}
printAllWithPrefix(
    "Hello", "Hallo", "Salut", "Hola", "你好",
    prefix = "Greeting: "                                          // 4
)

fun log(vararg entries: String) {
    printAll(*entries)                                             // 5
}

变量

kotlin 具有强大的变量的推断能力。你可以明确的定义变量的类型,也可以让编译器自己来推断变量类型是什么。推荐使用val 来定义变量,因为这是不变的变量,当然kotlin 也不会强制你将变量定义为不变,你可以使用var。

var a: String = "initial"  // 1
println(a)
val b: Int = 1             // 2
val c = 3                  // 3
var e: Int  // 1
println(e)  // 2

你可以在任何地方进行初始化,只要在read 这个变量之前就可以。这里和java 不同

val d: Int  // 1

if (someCondition()) {
    d = 1   // 2
} else {
    d = 2   // 2
}

println(d) // 3

空安全检查

kotlin 想要创造一个没有NullPointerException的世界,所以不允许给一个变量赋予Null值。如果你确实需要赋予一个变量null,请在他的类型名称之后加上?

var neverNull: String = "This can't be null"            // 1

neverNull = null                                        // 2

var nullable: String? = "You can keep a null here"      // 3

nullable = null                                         // 4

var inferredNonNull = "The compiler assumes non-null"   // 5

inferredNonNull = null                                  // 6

fun strLength(notNull: String): Int {                   // 7
    return notNull.length
}

strLength(neverNull)                                    // 8
strLength(nullable)                                     // 9
fun describeString(maybeString: String?): String {              // 1
    if (maybeString != null && maybeString.length > 0) {        // 2
        return "String of length ${maybeString.length}"
    } else {
        return "Empty or null string"                           // 3
    }
}

定义由类名,类头(包含类型声明,私有构造方法等)、和类体组成,并且由大括号组成。类头和类体都是可以缺省的。如果类体缺省,那么大括号也可以缺省。

class Customer                                  // 1

class Contact(val id: Int, var email: String)   // 2

fun main() {

    val customer = Customer()                   // 3
    
    val contact = Contact(1, "mary@gmail.com")  // 4

    println(contact.id)                         // 5
    contact.email = "jane@gmail.com"            // 6
}

泛型

泛型是现代语言都具有的一种模板方法。泛型类和泛型方法使得代码具有高度的可复用性。就像List<T>里卖弄的内部逻辑与T就没有什么逻辑上的关系

泛型类

第一种使用泛型的方法就是泛型类

class MutableStack<E>(vararg items: E) {              // 1

  private val elements = items.toMutableList() 

  fun push(element: E) = elements.add(element)        // 2

  fun peek(): E = elements.last()                     // 3

  fun pop(): E = elements.removeAt(elements.size - 1)

  fun isEmpty() = elements.isEmpty()

  fun size() = elements.size

  override fun toString() = "MutableStack(${elements.joinToString()})"
}
泛型方法

你当然也可以定义泛型方法,如果他们的逻辑与泛型参数无关的话。比如你可以定义一个这样的方法

fun <E> mutableStackOf(vararg elements: E) = MutableStack(*elements)

fun main() {
  val stack = mutableStackOf(0.62, 3.14, 2.7)
  println(stack)
}

注意:编译将会推断出mutableStackOf是一个Double的MutableStack所以你不需要填写mutableStackOf<Double>(...) 之类的


继承

kotlin 支持传统的面向对象的继承机制

open class Dog {                // 1
    open fun sayHello() {       // 2
        println("wow wow!")
    }
}

class Yorkshire : Dog() {       // 3
    override fun sayHello() {   // 4
        println("wif wif!")
    }
}

fun main() {
    val dog: Dog = Yorkshire()
    dog.sayHello()
}
带有参数的构造方法的继承
open class Tiger(val origin: String) {
    fun sayHello() {
        println("A tiger from $origin says: grrhhh!")
    }
}

class SiberianTiger : Tiger("Siberia")                  // 1

fun main() {
    val tiger: Tiger = SiberianTiger()
    tiger.sayHello()
}
传递参数给父类
open class Lion(val name: String, val origin: String) {
    fun sayHello() {
        println("$name, the lion from $origin says: graoh!")
    }
}

class Asiatic(name: String) : Lion(name = name, origin = "India") // 1

fun main() {
    val lion: Lion = Asiatic("Rufo")                              // 2
    lion.sayHello()
}
上一篇 下一篇

猜你喜欢

热点阅读