Kotlin 入门-基本语法
kotlin 作为 java 类似的语言,学过 java 的同学,学 kotlin 应该很轻松。
Package 和 Import
package
所有的 kotlin 源码都是从包名声明开始的,如下代码:
package com.kugou.kotlon.kotlinfirstglance
import android.support.v7.app.AppCompatActivity
class HomePageActivity extends AppCompatActivity{
.........................
}
kotlin 里面,所有的类,方法都是包名所有的,这意味着,类名是完整的,例如上面的完整类名是 com.kugou.kotlon.kotlinfirstglance.AppCompatActivity。
默认导入的包
根据不同的平台,kotlin 会在每个kotlin 源码文件导入不同的默认 package,例如下面是每个平台都会导入的默认包:
- kotlin.*
- kotlin.annotation.*
- kotlin.collections.*
- kotlin.comparisons.* (since 1.1)
- kotlin.io.*
- kotlin.ranges.*
- kotlin.sequences.*
- kotlin.text.*
import
在 kotlin 中 import 不仅仅可以用来导入包,也可以导入函数等,除了类还可以导入如下:
- top-level 函数和属性
- 在 Object declaration 声明的函数和属性
- 枚举场常量
as 关键字
AS 关键子可以和 import 搭配使用,用于重命名你导入的类,例如:
import foo.Bar // Bar is accessible
import bar.Bar as bBar // 将此包名下的bar重命名为 bBar,这个命名仅在此 kotlin 文件中生效
函数
函数定义和声明
使用关键字 fun,定义和声明函数,如下:
fun init(isShow: boolean){
........
}
这个函数返回类型是 Unit 的,如果没写返回类型,即是说这个函数的返回类型是 Unit,Unit 类型的函数没有返回值或者返回值可以是忽略的(和java 的void 相似)。
函数调用
可以直接调用:
init(true);//调用方式和 java 方法的调用方式一样
中缀符号
函数的可以通过Infix notations(中缀符号)调用,如果他们符合以下情况之一:
- 是一个成员函数或者扩展函数
- 只有一个函数参数
- 被 infix 关键字声明标记(只有成员函数和扩展函数才能被 infix 修饰)
class Tools{
infix fun convertStr(content:String){
}
fun toBuildNewStr(){
Tools() convertStr "hsh" //这里的调用方式便是中缀调用(此函数为成员函数),对象实例 函数名 参数
}
}
函数参数
函数参数声明格式,规范为帕斯卡符号
number:Int//参数名称:参数类型
默认参数
这个兼容了 python 等语言的特点,函数支持默认参数,这对减少方法重载提供了有意义的价值;具体的例子如下:
fun addLevel(level: Int = 1, isFxShow: Boolean){
}
默认参数的格式是,在函数参数的类型后面加上”=”,然后是默认的参数数值;需要注意的是,在方法重载的过程中,如果父类方法提供了某个参数的默认数值,那么在子类在重载这个方法的时候,就不能够再次对这个参数设置默认参数。
实名参数(Named Arguments)
在调用函数的时候,可以通过指定
注意:在调用 java 方法的时候,不可以使用实名参数,因为java 字节码通常不会保留java 方法参数的参数名称。
Unit 返回值的函数
如果一个参数没有指定返回值类型,则这个函数的返回值类型是 Unit 的,当然你也可以显式的指定返回类型为任何类型。Unit 在 kotlin 里面是
单行表达式函数
如果你的函数体只有一行代码,可以使用单行表达式函数,使用”=”连接函数名称和函数体,例子如下:
fun doubleInt(x: Int) = x * 2
可变参数
可变参数是众多语言支持的特性,kotlin 也支持这个特性,你可以在函数中使用 Varargs关键字声明可变参数,
fun <T> asList(vararg ts: T): List<T> {
val result = ArrayList<T>()
for (t in ts) // ts is an Array
result.add(t)
return result
}
总的来说,你可以像以下这样调用这个方法:
val list = asList(1, 2, 3)
如果你需要传入数组,则需要使用 Spread 操作符号,具体的例子如下:
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)// 这里的 a 即是数组,*a,表示取数组 a 里面的内容
注意,对于可变参数,一个函数中,只允许一个可变参数。
函数作用域
在 kotlin 中,函数可以在文件的头部进行声明,这样的函数不需要关联class,称为 top-level 顶层函数。除了 top level 函数之外,函数也可能被声明为局部函数(本地函数)local 的。如下是一个顶层函数和局部函数,其中 toBuildNewStr()是顶层函数,addStart()是local 函数。:
fun toBuildNewStr() {
}
class Tools {
fun addLevel(level: Int = 1, isFxShow: Boolean){
fun addStart(isStart: Boolean){
}
}
}
local 函数可以访问外层函数的任何变量。例如以下代码:
fun dfs(graph: Graph) {
val visited = HashSet<Vertex>()
fun dfs(current: Vertex) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v)
}
dfs(graph.vertices[0])
}
在上面的函数中, visited 可以被 dfs()函数直接访问。
成员函数
成员函数是相对于 class 来说的,例如以下是一个成员函数:
class Tools {
infix fun convertStr(content: String) {
}
}
泛型函数
kotlin 里面泛型函数和java 里面的泛型函数是一致的,在函数名前面使用”<>”替代类型声明,如下:
fun <T> singletonList(item: T): List<T> {
// ...
}
inline 函数(内联函数)
扩展函数(extension 函数)
Higher-Order 函数(高阶函数)
高阶函数,是现代语言支持的特性之一,函数也是一个对象,所以函数也可以作为方法参数。那么在实际的开发场景中,我们什么时候会用到高阶函数呢?
fun <T> lock(lock: Lock, body: () -> T): T {
lock.lock()// 这里是函数第一个参数
try {
return body()//函数第二个参数
}
finally {
lock.unlock()
}
}
这里 lock()是一个函数,第一个函数参数是一个 lock()对象,第二个参数是一个函数,我们可以这样调用这个方法:
fun toBeSynchronized() = sharedResource.operation()
val result = lock(lock, ::toBeSynchronized)// 这里的双冒号
也可以使用 lambdas 表达式的写法,如下:
val result = lock(lock, { sharedResource.operation() }) //花括号里面就是一个 lambdas,你可以理解为 lambdas 是一个简易的匿名函数,这是对函数式编程的应用之一。
lambdas 表达式和匿名函数
lambdas 表达式和匿名函数又称为“function literal”,函数字面量(js 里面也有这个说法)。简单来说,就是这个函数是没有声明的,但是作为一个表达式传递数值,例如以下代码:
max(strings, { a, b -> a.length < b.length })
这里的 max()是一个高阶函数,其第二个参数是一个函数类型的参数,我们这里传递的就是一个lambdas 表达式,这个表达式的常规写法是下面这样的:
fun compare(a: String, b: String): Boolean = a.length < b.length
lambdas 的特点有:
- 一个lambdas 表达式总是被花括号圈起来的
- 函数的参数在”->”之前(有过没有参数,则忽略,什么也不用写)
- 函数体在”->”之后
尾部递归函数(Tail recursive function)
属性和数据域
关键字 Var 和 Val
var 关键字用于定义变量,val 关键字定义只读常量。
数据类型
在 kotlin 中,任何东西都是对象,我们可以在任何变量上调用成员函数访问属性。看起来有些类型是内置的,只是因为这些内置的类型,提供了最好的优化实现,但是,对我们来说,他们更像常规类。
Numbers 类型
kotlin 在定义 numbers 类型时,采用了和 java 类似的机制,但是又不是完全相同的,例如,kotlin 不会对数据类型进行隐式转换(字符串字面量可能有点不一样)
type | Bit Width(宽度) |
---|---|
Double | 64 |
Float | 32 |
Long | 64 |
Int | 32 |
Short | 16 |
Byte | 8 |
和 java的基本类型有点不同,java 还多了 char 和 boolean 这两种基本类型。
Literal Constants字面常量
字符串模板
kotlin 里面提供了字符串模板,为字符串操作提供了强大的支持,这种操作类似于 adnroid 在 String.xml 里面防止各种占位符,然后进行字符串拼接,不错,kotlin 使用字符串模板是非常简便的。
简单的例子如下:
var number = 10
val content = "your number is $number" // 这里 content 的最终内容为 your number is 10
字符串模板使用美元符号”$”连接需要拼接的内容,不仅可以拼接字面常量,也可以拼接一个表达式,具体的示例如下:
var number = 10
val content = "you number is $ number"
val strLength = "length is ${content.length}"
如果,需要将美元符号”$”使用为字符常量,则需要使用类似 java 转义字符的操作,例如下面是一个例子:
val priceTip = "the price is ${'$'} 100"
字符串模板操作,支持原始字符串,也支持转移字符串。