kotlin language主页: http://kotlinlang.org/
kotlin在线编程网址: https://try.kotlinlang.org/#/Examples/Hello,%20world!/Simplest%20version/Simplest%20version.kt
kotlin官方文档:http://kotlinlang.org/docs/reference/
继上一个kotlin的插件下载配置后这是第二篇kotlin的文章,(再次说明一下,Android studio不是3.0或以上版本才是以插件的方式配置kotlin的,3.0版本就不用这样折腾了,看kotlin官网说明即知):
Tools for Android Development
The Kotlin team offers a set of tools for Android development that goes beyond the standard language features:
Kotlin Android Extensions is a compiler extension that allows you to get rid of findViewById() calls in your code and to replace them with synthetic compiler-generated properties.
Anko is a library providing a set of Kotlin-friendly wrappers around the Android APIs, as well as a DSL that lets your replace your layout .xml files with Kotlin code.
Next Steps
Download an install Android Studio 3.0 Preview, which includes Kotlin support out of the box.
Follow the Getting Started with Android and Kotlin tutorial to create your first Kotlin application.
For a more in-depth introduction, check out the reference documentation on this site and Kotlin Koans.
Another great resource is Kotlin for Android Developers, a book that guides you step by step through the process of creating a real Android application in Kotlin.
Check out Google's sample projects written in Kotlin.
Basic Syntax
一 defining packages 包结构的定义
Package specification should be at the top of the source file:
package my.demo
import java.util.*
// ...
It is not required to match directories and packages: source files can be placed arbitrarily in the file system.
See Packages.
包的引入必须是放在代码文件的最顶端的,这一点和Java么有什么差别。后面那句意思是,目录和包没有必要一定要匹配,代码文件可以放在文件系统的任意位置,我觉得这个意思就是说在代码文件当中引入packages的时候是不会受到路径制约的,其实就是Android studio环境下面能够自动根据引入的包来找到对应的资源。最后有一个进入到packages语法的链接,索性过去先看看packages部分的语法和Java有什么区别吧:
A source file may start with a package declaration:
package foo.bar
fun baz() {}
class Goo {}
// ...
All the contents (such as classes and functions) of the source file are contained by the package declared.So, in the example above, the full name of baz()
is foo.bar.baz
, and the full name of Goo
is foo.bar.Goo
.
If the package is not specified, the contents of such a file belong to "default" package that has no name.
代码文件里面的函数或者类,是引入的包里面的资源,如果没有在前面引入这个包,那么在代码的函数和类里面就要写上“全称“了,即,上述举例当中如果没有引入对应的packages就应该在代码当中写为:foo.bar.baz(),或者类的形式为:foo.bar.Goo,这样子了。这也说明了第一句话的意思(A source file may start with a package declaration)一个代码源文件当中可以引入packages,当然了也可以不引入,那么这就引出了下面的default imports的概念了。A number of packages are imported into every Kotlin file by default:
Additional packages are imported depending on the target platform:
Apart from the default imports, each file may contain its own import directives.Syntax for imports is described in the grammar.
We can import either a single name, e.g.
import foo.Bar // Bar is now accessible without qualification
or all the accessible contents of a scope (package, class, object etc):
import foo.* // everything in 'foo' becomes accessible
If there is a name clash, we can disambiguate by using as keyword to locally rename the clashing entity:
import foo.Bar // Bar is accessible
import bar.Bar as bBar // bBar stands for 'bar.Bar'
The import
keyword is not restricted to importing classes; you can also use it to import other declarations:
Unlike Java, Kotlin does not have a separate "import static" syntax; all of these declarations are imported using the regular import
keyword.
编写代码的时候,除了使用系统的API之外,还有一大堆是自己张罗的代码文件包括了很多的类/函数等等东西,因此在不同的文件之间就是需要通过imports的方式将这些需要互相调用的类等等引进来了,那么就是”imports“。引入的方式可以是具体的指向特定的名字,也可以是引入一个”区域“的资源。
另外值得注意的是上面黄色背景部分,如果是在引入的包当中有冲突的类的时候,可以使用”as“关键字进行申明区别。
If a top-level declaration is marked private, it is private to the file it's declared in (see Visibility Modifiers).
如果申明了private的话,那么在他所申明的文件里他就是属于私有的东西了。综上:package的这些相关语法和Java基本没差,只是其中有一个包冲突时候的“as”关键字的使用和Java不一样,Java里面好像没有,我没有使用过。
——————————————————————————————————————————————————————————————————————————
回到packages下面的函数申明和编写部分
二 定义函数
Int
parameters with
Int
return type:
fun sum(a: Int, b: Int): Int {
return a + b
}
可以看到函数的写法和Java的已经是大相径庭了,便于对比,我将上述的kotlin的函数敲成Java的函数如下:
public int sum(int a, int b){
return a+b;
}
通过对比发现,函数的申明变成了“fun”,而前面也没有类似Java的“public”或者“private”等作用域的限制关键字了,形参里面改用了“:“冒号作为形参类型和形参变量之间的对应,函数申明一行的后面又通过”:“冒号跟了一个返回值的类型,注意是Int而不是int哦!第一个字母大写了,这里返回值为int类型,另外,每一行的后面都没有了”;“分号作为一行/句代码的结尾标识。
再看看主函数的写法:
fun main(args: Array) {
print("sum of 3 and 5 is ")
println(sum(3, 5))
}
主函数的函数申明一行没有出现返回值的定义,那么就是说明,如果没有返回值的话,函数申明一行是不需要添加冒号+返回值类型这个的。主函数部分主要看看函数体里面的输出打印语句print和println两个函数,这两行看起来都是比较正常的,一个输出了字符串,接着第二行调用函数赋值然后输出赋值后的运算结果。但其中有一个肯定有换行功能的,不知道是不是和Java下的println是不是一样的,自己写一下测试了,println是带换行的那个,这里顺便丢一张kotlin在线编程的界面:
接着看第二种函数申明格式:函数的申明和函数体都写在了一起,返回值可以推断。
Function with an expression body and inferred return type:
fun sum(a: Int, b: Int) = a + b
fun main(args: Array) {
println("sum of 19 and 23 is ${sum(19, 23)}")
}
这个函数没有申明返回值类型,主函数体的println里面出现了一个”$“符号调用上面的函数,并传值了。这个”$“的作用也很明显了,但是注意通过”$"调用函数的时候是通过“{~~}”括起来的。那么在继”:“冒号之后这是第二个新的符号出现了。通过测试发现这样的申明形式虽然没有返回值申明,但应该是默认了Int类型了,但是如果形参里面是两种不同类型的参与运算就会报错了:
Simplest version.kt
Error:(9, 16) The integer literal does not conform to the expected type Float
Function returning no meaningful value:
fun printSum(a: Int, b: Int): Unit {
println("sum of $a and $b is ${a + b}")
}
fun main(args: Array) {
printSum(-1, 8)
}
函数体里面的println语句通过“$”做了一个简单的运算。
第四种函数格式:返回值可忽略
Unit
return type can be omitted:
fun printSum(a: Int, b: Int) {
println("sum of $a and $b is ${a + b}")
}
fun main(args: Array) {
printSum(-1, 8)
}
和上一个一样,只是说明了Unit的返回值的话,可以将其忽略掉不写。
三,变量声明
Assign-once (read-only) local variable:
fun main(args: Array) {
val a: Int = 1 // immediate assignment
val b = 2 // `Int` type is inferred
val c: Int // Type required when no initializer is provided
c = 3 // deferred assignment
println("a = $a, b = $b, c = $c")
}
可变变量赋值
Mutable variable:
fun main(args: Array) {
var x = 5 // `Int` type is inferred
x += 1
println("x = $x")
}
三, 注释
Just like Java and JavaScript, Kotlin supports end-of-line and block comments.
// This is an end-of-line comment
/* This is a block comment
on multiple lines. */
Unlike Java, block comments in Kotlin can be nested.
注释和Java一样,就是两种形式:// 一行的注释,/**/ 多行注释。不过不同于Java的多行注释不能嵌套存在,kotlin的多行注释是可以嵌套的哦。
四,字符串相关定义和使用
fun main(args: Array) {
var a = 1
// simple name in template:
val s1 = "a is $a"
a = 2
// arbitrary expression in template:
val s2 = "${s1.replace("is", "was")}, but now is $a"
println(s2)
}
函数体里面有个replace方法,和Java一样的。
五,条件表达式的使用
fun maxOf(a: Int, b: Int): Int {
if (a > b) {
return a
} else {
return b
}
}
六,重要特性:可为空的值的使用和检查是否为空
A reference must be explicitly marked as nullable when null value is possible.
特别注意,当一个值可为空的时候,必须明确标明其可为空!
Return null if str
does not hold an integer:
fun parseInt(str: String): Int? {
// ...
}
fun parseInt(str: String): Int? {
return str.toIntOrNull()
}
fun printProduct(arg1: String, arg2: String) {
val x = parseInt(arg1)
val y = parseInt(arg2)
// Using `x * y` yields error because they may hold nulls.
if (x != null && y != null) {
// x and y are automatically cast to non-nullable after null check
println(x * y)
}
else {
println("either '$arg1' or '$arg2' is not a number")
}
}
fun main(args: Array) {
printProduct("6", "7")
printProduct("a", "7")
printProduct("a", "b")
}
or
fun parseInt(str: String): Int? {
return str.toIntOrNull()
}
fun printProduct(arg1: String, arg2: String) {
val x = parseInt(arg1)
val y = parseInt(arg2)
// ...
if (x == null) {
println("Wrong number format in arg1: '${arg1}'")
return
}
if (y == null) {
println("Wrong number format in arg2: '${arg2}'")
return
}
// x and y are automatically cast to non-nullable after null check
println(x * y)
}
fun main(args: Array) {
printProduct("6", "7")
printProduct("a", "7")
printProduct("99", "b")
}
这便是kotlin的”空安全“机制,详见:http://kotlinlang.org/docs/reference/null-safety.html
七,类型检查和自动转换
通过”is“关键字/运算符来检查表达式左边是否是右边类型的一个实例,如果是特定类型检查局部变量或者属性,则不需要显示的转换
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// `obj` is automatically cast to `String` in this branch
return obj.length
}
// `obj` is still of type `Any` outside of the type-checked branch
return null
}
fun main(args: Array) {
fun printLength(obj: Any) {
println("'$obj' string length is ${getStringLength(obj) ?: "... err, not a string"} ")
}
printLength("Incomprehensibilities")
printLength(1000)
printLength(listOf(Any()))
}
or
fun getStringLength(obj: Any): Int? {
if (obj !is String) return null
// `obj` is automatically cast to `String` in this branch
return obj.length
}
fun main(args: Array) {
fun printLength(obj: Any) {
println("'$obj' string length is ${getStringLength(obj) ?: "... err, not a string"} ")
}
printLength("Incomprehensibilities")
printLength(1000)
printLength(listOf(Any()))
}
or even
fun getStringLength(obj: Any): Int? {
// `obj` is automatically cast to `String` on the right-hand side of `&&`
if (obj is String && obj.length > 0) {
return obj.length
}
return null
}
fun main(args: Array) {
fun printLength(obj: Any) {
println("'$obj' string length is ${getStringLength(obj) ?: "... err, is empty or not a string at all"} ")
}
printLength("Incomprehensibilities")
printLength("")
printLength(1000)
}
//类型后面加?表示可为空
var age: String? = "23"
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1
其中的”?“符号是可为空,”!!“是像Java一样抛出空异常,"?:"则是再进行判断”如果为空,则执行后面那句“。
八,for 循环
for
loopfun main(args: Array) {
val items = listOf("apple", "banana", "kiwi")
for (item in items) {
println(item)
}
}
fun main(args: Array) {
val items = listOf("apple", "banana", "kiwi")
for (index in items.indices) {
println("item at $index is ${items[index]}")
}
}
withIndex
“:
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
while
loopfun main(args: Array) {
val items = listOf("apple", "banana", "kiwi")
var index = 0
while (index < items.size) {
println("item at $index is ${items[index]}")
index++
}
}
when
expressionfun describe(obj: Any): String =
when (obj) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}
fun main(args: Array) {
println(describe(1))
println(describe("Hello"))
println(describe(1000L))
println(describe(2))
println(describe("other"))
}
十一,ranges
fun main(args: Array) {
val x = 10
val y = 9
if (x in 1..y+1) {
println("fits in range")
}
}
看上去是作为判断范围的,自己写了下,这个范围是个闭区间。注意其中的关键字”in“和”.."
一个用于判断数字是否在某个范围的例子:
fun main(args: Array) {
val list = listOf("a", "b", "c")
if (-1 !in 0..list.lastIndex) {
println("-1 is out of range")
}
if (list.size !in list.indices) {
println("list size is out of valid list indices range too")
}
println("${list.size} and ${list.indices}")
}
上面最后一行代码打印出的结果值得注意一下:
3 and 0..2
这个新特性用于循环打印输出的例子:
fun main(args: Array) {
for (x in 1..5) {
print(x)
}
}
fun main(args: Array) {
for (x in 1..10 step 2) {
print(x)
}
for (x in 9 downTo 0 step 3) {
print(x)
}
}
注意后面那个函数使用了“step”步长以及“downTo”向下输出,感觉好像很实用。
十二,集合的使用
fun main(args: Array) {
val items = listOf("apple", "banana", "kiwi")
for (item in items) {
println(item)
}
}
使用“in”检查集合当中是否含有这个object。Checking if a collection contains an object using
in operator:
fun main(args: Array) {
val items = setOf("apple", "banana", "kiwi")
when {
"orange" in items -> println("juicy")
"apple" in items -> println("apple is fine too")
}
}
fun main(args: Array) {
val fruits = listOf("banana", "avocado", "apple", "kiwi")
fruits
.filter { it.startsWith("a") }
.sortedBy { it }
.map { it.toUpperCase() }
.forEach { println(it) }
}
好了,以上就是这些基本语法,大致过了一遍,里面还有各个点的细节介绍还没看。有和Java类似的,但大部分都是新的东西。