最近在Safari Book Online上閱讀Big Nerd Ranch Guide的Kotlin Programming一書棵譬。此書寫得非常精彩乙嘀,雖然是從最基礎的語法開始交起末购,對于我這個有著十載編程經(jīng)驗的人,依然很有收獲虎谢。由于Kotlin的知識點非常多招盲,大腦無法在短時間沒有實作的鞏固下牢記。所以留以此文已備參考嘉冒。
第一章:Your First Kotlin Application
首先JetBrains出產(chǎn)的IntelliJ IDEA是編寫Kotlin程序不二的選擇。為什么咆繁?
IntelliJ IDEA, called IntelliJ for short, helps you write well-formed Kotlin code. It also streamlines the development process with built-in tools for running, debugging, inspecting, and refactoring your code.
IntelliJ的項目
A project includes all of the source code for your program, along with information about dependencies and configurations. A project can be broken down into one or more modules, which are like subprojects. By default, a new project has one module, which is all you need for your simple first project.
Sandbox
項目的結(jié)構(gòu)
The Sandbox.iml file contains configuration information specific to your single module. The .idea folder contains settings files for the entire project as well as those specific to your interaction with the project in the IDE (for example, which files you have open in the editor). Leave these auto-generated files as they are.
Sandbox.iml
文件是針對單個模塊的讳推,包含該模塊配置信息。.idea
文件夾包含整個項目的設置和你與項目在IDE中交互設置文件玩般。
The External Libraries entry contains information about libraries the project depends on. If you expand this entry you will see that IntelliJ automatically added Java 1.8 and KotlinJavaRuntime as dependencies for your project.
接下來是教授任何一門新語言的第一個程序:Hello World程序银觅。創(chuàng)建Hello.kt
并鍵入:
fun main(args: Array<String>) {
println("Hello, world!")
}
注意:IntelliJ提供了一個編寫main
函數(shù)樁代碼的快捷方式,輸入單詞main
然后按下Tab
鍵坏为。
相比Java究驴,Kotlin做最簡單的事情,也比Java簡單很多匀伏,不再像“萬物皆對象”那樣洒忧,為一個簡單的Hello World程序也要創(chuàng)建一個類,把函數(shù)包進類定義中够颠。Kotlin也不再稱main為方法(method)熙侍,而是函數(shù)(function)。
This particular function – the main function indicates the starting place for your program. This is called the application entry point, and one such entry point must be defined for any program to be runnable.
println()是Kotlin標準庫(Kotlin standard library)的一個內(nèi)建函數(shù)履磨。
Kotlin/JVM代碼的編譯與執(zhí)行
按下運行HelloKt
按鈕知道控制臺輸出Hello, World!
之間蛉抓,幕后發(fā)生了很多事。
First, IntelliJ compiles the Kotlin code using the
kotlinc-jvm
compiler. This means IntelliJ translates the Kotlin code you wrote into bytecode, the language the JVM “speaks.” Ifkotlinc-jvm
has any problems translating your Kotlin code, it will display an error message (or messages) giving you a hint about how to fix the issues. Otherwise, if the compilation process goes smoothly, IntelliJ moves on to the execution phase.
In the execution phase, the bytecode that was generated by
kotlinc-jvm
is executed on the JVM. The console displays any output from your program, such as printing the text you specified in your call to the println() function, as the JVM executes the instructions.
When there are no more bytecode instructions to execute, the JVM terminates. IntelliJ shows the termination status in the console, letting you know whether execution finished successfully or with an error code.
The Kotlin REPL
Kotlin REPL的話剃诅,目前還很難感知它的實用性巷送,不過記住它的入口是Tools->Kotlin->Kotlin REPL
,還有記住在REPL中evaluate代碼的快捷鍵:Command-Return (Ctrl-Return)
For the More Curious: Why Use IntelliJ?
曾記得十年前初學Java時矛辕,我是習慣使用普通的文本編輯器(EditPlus)編寫Java示例代碼的笑跛。Kotlin當然也可以使用text editor編寫,但是此書作者建議初學者使用IntelliJ聊品。如此來看堡牡,Kotlin淪陷為最好在IDE中編寫程序的語言了。確實IntelliJ非常的智能杨刨,程序員仰賴IntelliJ對代碼進行的細致的檢測以寫出語法正確的代碼晤柄。正如該節(jié)末尾所指出的:
Also, since Kotlin was created by JetBrains, the integration between IntelliJ and Kotlin is carefully designed – often leading to a delightful editing experience.
For the More Curious: Targeting the JVM
The JVM is a piece of software that knows how to execute a set of instructions, called bytecode. “Targeting the JVM” means compiling, or translating, your Kotlin source code into Java bytecode, with the intention of running that bytecode on the JVM.
Since Kotlin can be converted to bytecode that the JVM can execute, it is considered a JVM language. Java is perhaps the most well-known JVM language, because it was the first. However, other JVM languages, such as Scala and Kotlin, have emerged to address some shortcomings of Java from the developer perspective.
Kotlin is not limited to the JVM, however. At the time of this writing, Kotlin can also be compiled into JavaScript or even into native binaries that run directly on a given platform – such as Windows, Linux, and macOS – negating the need for a virtual machine layer.
第二章:變量、常量和類型(Types)
Types describe the particular kind of data that is held by a constant or variable.
變量和常量有一個指定的數(shù)據(jù)類型妖胀,告訴了編譯器如何處理type checking
type checking will be handled, a feature in Kotlin that prevents the assignment of the wrong kind of data to a variable or constant.
聲明一個變量
Kotlin使用var
來聲明變量芥颈,如果編譯器能夠推斷出變量的具體類型惠勒,那么類型就可以不用聲明。比如:
fun main(args: Array<String>) {
var experiencePoints: Int = 5
println(experiencePoints)
}
也可以簡化成:
fun main(args: Array<String>) {
var experiencePoints = 5
println(experiencePoints)
}
似乎IntelliJ并不鼓勵在可以推斷類型的情況下顯示聲明類型爬坑。
Kotlin uses a static type system – meaning the compiler labels the source code you define with types so that it can ensure the code you wrote is valid. IntelliJ also checks code as you type it and notices when an instance of a particular type is incorrectly assigned to a variable of a different type. This feature is called static type checking, and it tells you about programming mistakes before you even compile the program.
Kotlin's Built-in Types
Kotlin的內(nèi)建數(shù)據(jù)類型有String
, Char
, Boolean
, Int
, Double
, List
, Set
, Map
纠屋,雖然這些類型在Java中也有,但是要記住這些是Kotlin自己定義的類型盾计。
Read-only Variables只讀變量
You declare a variable that can be modified using the var keyword. To declare a read-only variable, you use the val keyword.
var
關鍵字的引入售担,就我來看,是起到強促程序員多多使用常量署辉。就像作者所說:
...we recommend that you use a val any time you do not need a var.
IntelliJ can detect when a var can be made a val instead by analyzing your code statically. If a var is never changed, IntelliJ will suggest that you convert it to a val.
To apply the suggestion, click on the var keyword next to playerName and press Option-Return (Alt-Enter). In the pop-up, select Make variable immutable
Type inference
Kotlin includes a feature called type inference that allows you to omit the type definition for variables that are assigned a value when they are declared.
Note that IntelliJ will display the type of any variable on request, including those that use type inference. If you ever have a question about the type of a variable, click on its name and press Control-Shift-P. IntelliJ will display its type.
Compile-Time Constants
val
聲明的數(shù)據(jù)并不一定是不可改變的常量族铆,如果要讓數(shù)據(jù)絕對不可變,要考慮用編譯時常量哭尝。
A compile-time constant must be defined outside of any function, including main, because its value must be assigned at compile time (that is, when the program compiles) – hence the name. main and your other functions are called during runtime (when the program is executed), and the variables within them are assigned their values then. A compile-time constant exists before any of these assignments take place.
Compile-time constants also must be of one of the basic types(String, Int, Double, Float, Long, Short, Byte, Char, Boolean), because use of more complex types for a constant could jeopardize the compile-time guarantee.
const val MAX_EXPERIENCE: Int = 5000
fun main(args: Array<String>) {
...
}
這里定義的變量并不是local to a function or class – a file-level variable哥攘。
Prepending a val with the const modifier tells the compiler that it can be sure that this val will never change. In this case, MAX_EXPERIENCE is guaranteed to have the integer value 5000, no matter what. This gives the compiler the flexibility to perform optimization behind the scenes.
Inspecting Kotlin Bytecode
Kotlin is an alternative to Java for writing programs that run on the JVM, where Java bytecode is executed. It is often useful to inspect the Java bytecode that the Kotlin compiler generates to run on the JVM. You will look at the bytecode in several places in this book as a way to analyze how a particular language feature works on the JVM.
Knowing how to inspect the Java equivalent of the Kotlin code you write is a great technique for understanding how Kotlin works, especially if you have Java experience.
For the More Curious: Java Primitive Types in Kotlin
Java中有Primitive類型和Reference類型。引入Primitive Types是出于性能考量:實例化開銷材鹦、內(nèi)存占用都會小很多...逝淹;Kotlin僅提供一種數(shù)據(jù)類型:Reference類型。
Kotlin made this design decision for several reasons. First, if there is no choice between kinds of types, you cannot code yourself into a corner as easily as you can with multiple kinds to choose from. For example, what if you define an instance of a primitive type, then realize later that you need to use the generic feature, which requires a reference type? Having only reference types in Kotlin means that you will never encounter this problem.
Kotlin編譯器會將可以轉(zhuǎn)換為Primitive類型的應用類型轉(zhuǎn)換為Primitive類型
var experiencePoints: Int = 5
會被轉(zhuǎn)換成
int experiencePoints = 5;
Kotlin gives you the ease of reference types with the performance of primitives under the hood. In Kotlin you will find a corresponding reference type for the eight primitive types you may be familiar with in Java.
第三章:Conditionals
==
在Kotlin中是結(jié)構(gòu)相等操作符(Structural equality operator)桶唐,被讀作“相等”栅葡。
Using the addition operator (
+
) to append a value to a string is called string concatenation. It is an easy way to customize what is printed to the console based on the value of a variable.
+
運算符在字符串上被重載為字符串拼接操作,Kotlin推薦使用String templating
來把值注入到字符串內(nèi)尤泽。
Ranges
雖然Java中也可以寫一個自定義的Range類來支持表示“范圍”的概念妥畏,但是Kotlin是從語言級別上支持這個概念。如果不是從語言級別上支持的話安吁,任何的模仿只是拙劣的模仿醉蚁。
Kotlin provides ranges to represent a linear series of values.
In addition to the .. operator, several functions exist for creating ranges. The downTo function creates a range that descends rather than ascends, for example. And the until function creates a range that excludes the upper bound of the range specified.
... use the
in
keyword to check whether a value is within a range...
when表達式
竊以為,when
是Kotlin作者對Java中的switch
的改進鬼店。
By default, a when expression behaves as though there were a == equality operator between the argument you provide in parentheses and the conditions you specify in the curly braces.
val healthStatus = when (healthPoints) {
100 -> "is in excellent condition!"
in 90..99 -> "has a few scratches."
in 75..89 -> if (isBlessed) {
"has some minor wounds but is healing quite quickly!"
} else {
"has some minor wounds."
}
in 15..74 -> "looks pretty hurt."
else -> "is in awful condition!"
}
String Templates字符串模板
Kotlin features string templates to aid in this common need and, again, make your code more readable. Templates allow you to include the value of a variable inside a string’s quotation marks.
$ symbol indicates to Kotlin that you would like to template a val or var within a string you define, and it is provided as a convenience.
Kotlin also allows you to evaluate an expression within a string and interpolate the result – that is, to insert the result into the string. Any expression that you add within the curly braces after a dollar-sign character (
${}
) will be evaluated as a part of the string.
println("(Aura: $auraColor) (Blessed: ${if (isBlessed) "YES" else "NO"})")
println("$name $healthStatus")
第四章:函數(shù)
把重復執(zhí)行的語句提取并重構(gòu)成方法是IntelliJ提供的便利:
Control-click (right-click) on the code you selected and choose Refactor → Extract → Function…
Anatomy of a Function
A function can optionally begin with a visibility modifier. The visibility modifier determines which other functions can “see” – and therefore use – the function.
By default, a function’s visibility is public – meaning that all other functions (including functions defined in other files) can use the function. In other words, if you do not specify a modifier for the function, the function is considered public.
For each parameter, the definition also specifies the type of data it requires.
在方法頭网棍,參數(shù)的定義是必須指定數(shù)據(jù)類型的,不可以依賴類型推斷妇智。
Note that function parameters are always read-only – they do not support reassignment within the function body. In other words, within the body of a function, a function parameter is a val, instead of a var.
The file-level variable can be accessed from anywhere in the project (though a visibility modifier can be added to the declaration to change its visibility level). File-level variables remain initialized until program execution stops.
Because of the differences between local and file-level variables, the compiler enforces different requirements on when they must be assigned an initial value, or initialized.
File-level variables must always be assigned when they are defined, or the code will not compile. This requirement protects you from unexpected – and unwanted – behavior, like a variable not having a value when you try to use it.
Since a local variable is more limited in where it can be used – within the scope of the function in which it is defined – the compiler is more lenient about when it must be initialized. A local variable only has to be initialized before it is used.
Default Arguments默認實參
...you can assign a default value for a parameter that will be assigned if no argument is specified.
private fun castFireball(numFireballs: Int = 2) {
println("A glass of Fireball springs into existence. (x$numFireballs)")
}
castFireball(5)
castFireball()
Single-Expression Functions
For single-expression functions, you can omit the return type, curly braces, and return statement.
private fun castFireball(numFireballs: Int = 2) =
println("A glass of Fireball springs into existence. (x$numFireballs)")
Notice that instead of using the function body to specify the work the function will perform, with single-expression function syntax you use the assignment operator (=), followed by the expression.