3.6 代碼注釋
正如 Java 和 JavaScript想暗,Kotlin 支持行注釋及塊注釋妇汗。
// 這是一個行注釋
/* 這是一個多行的
塊注釋。 */
與 Java 不同的是说莫,Kotlin 的塊注釋可以嵌套杨箭。就是說,你可以這樣注釋:
/**
* hhhh
* /**
* fff
* /**
* ggggg
* */
* */
*
* abc
*
*/
fun main(args:Array<String>){
val f = Functions()
println(f.fvoid1())
println(f.fvoid2())
println(f.sum1(1,1))
println(f.sum2(1,1))
}
3.7 語法與標(biāo)識符
我們知道储狭,任何一門編程語言都會有一些自己專用的關(guān)鍵字互婿、符號以及規(guī)定的語法規(guī)則等等。程序員們使用這些基礎(chǔ)詞匯和語法規(guī)則來表達(dá)算法步驟辽狈,也就是寫代碼的過程慈参。
詞法分析是編譯器對源碼進(jìn)行編譯的基礎(chǔ)步驟之一。詞法分析是將源程序讀入的字符序列刮萌,按照一定的規(guī)則轉(zhuǎn)換成詞法單元(Token)序列的過程驮配。詞法單元是語言中具有獨立意義的最小單元,包括修飾符着茸、關(guān)鍵字壮锻、常數(shù)、運算符元扔、邊界符等等躯保。
3.7.1 修飾符
在Kotlin源碼工程中的kotlin/grammar/src/modifiers.grm文件中,描述了Kotlin語言的修飾符澎语,我們在此作簡要注釋說明:
/**
## Modifiers
*/
modifiers
: (modifier | annotations)*
;
typeModifiers
: (suspendModifier | annotations)*
;
modifier
: classModifier
: accessModifier
: varianceAnnotation
: memberModifier
: parameterModifier
: typeParameterModifier
: functionModifier
: propertyModifier
;
classModifier 類修飾符
: "abstract" 抽象類
: "final" 不可被繼承final類
: "enum" 枚舉類
: "open" 可繼承open類
: "annotation" 注解類
: "sealed" 密封類
: "data" 數(shù)據(jù)類
;
memberModifier
: "override" 重寫函數(shù)
: "open" 可被重寫
: "final" 不可被重寫
: "abstract" 抽象函數(shù)
: "lateinit" 后期初始化
;
accessModifier 訪問權(quán)限控制, 默認(rèn)是public
: "private"
: "protected"
: "public"
: "internal" 整個模塊內(nèi)(模塊(module)是指一起編譯的一組 Kotlin 源代碼文件: 例如途事,一個 IntelliJ IDEA 模塊验懊,一個 Maven 工程, 或 Gradle 工程,通過 Ant 任務(wù)的一次調(diào)用編譯的一組文件等)可訪問
;
varianceAnnotation 泛型可變性
: "in"
: "out"
;
parameterModifier
: "noinline"
: "crossinline"
: "vararg" 變長參數(shù)
;
typeParameterModifier
: "reified"
;
functionModifier
: "tailrec" 尾遞歸
: "operator"
: "infix"
: "inline"
: "external"
: suspendModifier
;
propertyModifier
: "const"
;
suspendModifier
: "suspend"
;
這些修飾符的完整定義尸变,在kotlin/compiler/frontend/src/org/jetbrains/kotlin/lexer/KtTokens.java源碼中:
KtModifierKeywordToken[] MODIFIER_KEYWORDS_ARRAY =
new KtModifierKeywordToken[] {
ABSTRACT_KEYWORD, ENUM_KEYWORD, OPEN_KEYWORD, INNER_KEYWORD, OVERRIDE_KEYWORD, PRIVATE_KEYWORD,
PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD, OUT_KEYWORD, IN_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD,
REIFIED_KEYWORD, COMPANION_KEYWORD, SEALED_KEYWORD, LATEINIT_KEYWORD,
DATA_KEYWORD, INLINE_KEYWORD, NOINLINE_KEYWORD, TAILREC_KEYWORD, EXTERNAL_KEYWORD, ANNOTATION_KEYWORD, CROSSINLINE_KEYWORD,
CONST_KEYWORD, OPERATOR_KEYWORD, INFIX_KEYWORD, SUSPEND_KEYWORD, HEADER_KEYWORD, IMPL_KEYWORD
};
TokenSet MODIFIER_KEYWORDS = TokenSet.create(MODIFIER_KEYWORDS_ARRAY);
TokenSet TYPE_MODIFIER_KEYWORDS = TokenSet.create(SUSPEND_KEYWORD);
TokenSet TYPE_ARGUMENT_MODIFIER_KEYWORDS = TokenSet.create(IN_KEYWORD, OUT_KEYWORD);
TokenSet RESERVED_VALUE_PARAMETER_MODIFIER_KEYWORDS = TokenSet.create(OUT_KEYWORD, VARARG_KEYWORD);
TokenSet VISIBILITY_MODIFIERS = TokenSet.create(PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD);
3.7.2 關(guān)鍵字(保留字)
TokenSet KEYWORDS = TokenSet.create(PACKAGE_KEYWORD, AS_KEYWORD, TYPE_ALIAS_KEYWORD, CLASS_KEYWORD, INTERFACE_KEYWORD,
THIS_KEYWORD, SUPER_KEYWORD, VAL_KEYWORD, VAR_KEYWORD, FUN_KEYWORD, FOR_KEYWORD,
NULL_KEYWORD,
TRUE_KEYWORD, FALSE_KEYWORD, IS_KEYWORD,
IN_KEYWORD, THROW_KEYWORD, RETURN_KEYWORD, BREAK_KEYWORD, CONTINUE_KEYWORD, OBJECT_KEYWORD, IF_KEYWORD,
ELSE_KEYWORD, WHILE_KEYWORD, DO_KEYWORD, TRY_KEYWORD, WHEN_KEYWORD,
NOT_IN, NOT_IS, AS_SAFE,
TYPEOF_KEYWORD
);
TokenSet SOFT_KEYWORDS = TokenSet.create(FILE_KEYWORD, IMPORT_KEYWORD, WHERE_KEYWORD, BY_KEYWORD, GET_KEYWORD,
SET_KEYWORD, ABSTRACT_KEYWORD, ENUM_KEYWORD, OPEN_KEYWORD, INNER_KEYWORD,
OVERRIDE_KEYWORD, PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD,
CATCH_KEYWORD, FINALLY_KEYWORD, OUT_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD, REIFIED_KEYWORD,
DYNAMIC_KEYWORD, COMPANION_KEYWORD, CONSTRUCTOR_KEYWORD, INIT_KEYWORD, SEALED_KEYWORD,
FIELD_KEYWORD, PROPERTY_KEYWORD, RECEIVER_KEYWORD, PARAM_KEYWORD, SETPARAM_KEYWORD,
DELEGATE_KEYWORD,
LATEINIT_KEYWORD,
DATA_KEYWORD, INLINE_KEYWORD, NOINLINE_KEYWORD, TAILREC_KEYWORD, EXTERNAL_KEYWORD,
ANNOTATION_KEYWORD, CROSSINLINE_KEYWORD, CONST_KEYWORD, OPERATOR_KEYWORD, INFIX_KEYWORD,
SUSPEND_KEYWORD, HEADER_KEYWORD, IMPL_KEYWORD
);
其中义图,對應(yīng)的關(guān)鍵字如下:
KtKeywordToken PACKAGE_KEYWORD = KtKeywordToken.keyword("package");
KtKeywordToken AS_KEYWORD = KtKeywordToken.keyword("as");
KtKeywordToken TYPE_ALIAS_KEYWORD = KtKeywordToken.keyword("typealias");
KtKeywordToken CLASS_KEYWORD = KtKeywordToken.keyword("class");
KtKeywordToken THIS_KEYWORD = KtKeywordToken.keyword("this");
KtKeywordToken SUPER_KEYWORD = KtKeywordToken.keyword("super");
KtKeywordToken VAL_KEYWORD = KtKeywordToken.keyword("val");
KtKeywordToken VAR_KEYWORD = KtKeywordToken.keyword("var");
KtKeywordToken FUN_KEYWORD = KtKeywordToken.keyword("fun");
KtKeywordToken FOR_KEYWORD = KtKeywordToken.keyword("for");
KtKeywordToken NULL_KEYWORD = KtKeywordToken.keyword("null");
KtKeywordToken TRUE_KEYWORD = KtKeywordToken.keyword("true");
KtKeywordToken FALSE_KEYWORD = KtKeywordToken.keyword("false");
KtKeywordToken IS_KEYWORD = KtKeywordToken.keyword("is");
KtModifierKeywordToken IN_KEYWORD = KtModifierKeywordToken.keywordModifier("in");
KtKeywordToken THROW_KEYWORD = KtKeywordToken.keyword("throw");
KtKeywordToken RETURN_KEYWORD = KtKeywordToken.keyword("return");
KtKeywordToken BREAK_KEYWORD = KtKeywordToken.keyword("break");
KtKeywordToken CONTINUE_KEYWORD = KtKeywordToken.keyword("continue");
KtKeywordToken OBJECT_KEYWORD = KtKeywordToken.keyword("object");
KtKeywordToken IF_KEYWORD = KtKeywordToken.keyword("if");
KtKeywordToken TRY_KEYWORD = KtKeywordToken.keyword("try");
KtKeywordToken ELSE_KEYWORD = KtKeywordToken.keyword("else");
KtKeywordToken WHILE_KEYWORD = KtKeywordToken.keyword("while");
KtKeywordToken DO_KEYWORD = KtKeywordToken.keyword("do");
KtKeywordToken WHEN_KEYWORD = KtKeywordToken.keyword("when");
KtKeywordToken INTERFACE_KEYWORD = KtKeywordToken.keyword("interface");
// Reserved for future use:
KtKeywordToken TYPEOF_KEYWORD = KtKeywordToken.keyword("typeof");
...
KtKeywordToken FILE_KEYWORD = KtKeywordToken.softKeyword("file");
KtKeywordToken FIELD_KEYWORD = KtKeywordToken.softKeyword("field");
KtKeywordToken PROPERTY_KEYWORD = KtKeywordToken.softKeyword("property");
KtKeywordToken RECEIVER_KEYWORD = KtKeywordToken.softKeyword("receiver");
KtKeywordToken PARAM_KEYWORD = KtKeywordToken.softKeyword("param");
KtKeywordToken SETPARAM_KEYWORD = KtKeywordToken.softKeyword("setparam");
KtKeywordToken DELEGATE_KEYWORD = KtKeywordToken.softKeyword("delegate");
KtKeywordToken IMPORT_KEYWORD = KtKeywordToken.softKeyword("import");
KtKeywordToken WHERE_KEYWORD = KtKeywordToken.softKeyword("where");
KtKeywordToken BY_KEYWORD = KtKeywordToken.softKeyword("by");
KtKeywordToken GET_KEYWORD = KtKeywordToken.softKeyword("get");
KtKeywordToken SET_KEYWORD = KtKeywordToken.softKeyword("set");
KtKeywordToken CONSTRUCTOR_KEYWORD = KtKeywordToken.softKeyword("constructor");
KtKeywordToken INIT_KEYWORD = KtKeywordToken.softKeyword("init");
KtModifierKeywordToken ABSTRACT_KEYWORD = KtModifierKeywordToken.softKeywordModifier("abstract");
KtModifierKeywordToken ENUM_KEYWORD = KtModifierKeywordToken.softKeywordModifier("enum");
KtModifierKeywordToken OPEN_KEYWORD = KtModifierKeywordToken.softKeywordModifier("open");
KtModifierKeywordToken INNER_KEYWORD = KtModifierKeywordToken.softKeywordModifier("inner");
KtModifierKeywordToken OVERRIDE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("override");
KtModifierKeywordToken PRIVATE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("private");
KtModifierKeywordToken PUBLIC_KEYWORD = KtModifierKeywordToken.softKeywordModifier("public");
KtModifierKeywordToken INTERNAL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("internal");
KtModifierKeywordToken PROTECTED_KEYWORD = KtModifierKeywordToken.softKeywordModifier("protected");
KtKeywordToken CATCH_KEYWORD = KtKeywordToken.softKeyword("catch");
KtModifierKeywordToken OUT_KEYWORD = KtModifierKeywordToken.softKeywordModifier("out");
KtModifierKeywordToken VARARG_KEYWORD = KtModifierKeywordToken.softKeywordModifier("vararg");
KtModifierKeywordToken REIFIED_KEYWORD = KtModifierKeywordToken.softKeywordModifier("reified");
KtKeywordToken DYNAMIC_KEYWORD = KtKeywordToken.softKeyword("dynamic");
KtModifierKeywordToken COMPANION_KEYWORD = KtModifierKeywordToken.softKeywordModifier("companion");
KtModifierKeywordToken SEALED_KEYWORD = KtModifierKeywordToken.softKeywordModifier("sealed");
KtModifierKeywordToken DEFAULT_VISIBILITY_KEYWORD = PUBLIC_KEYWORD;
KtKeywordToken FINALLY_KEYWORD = KtKeywordToken.softKeyword("finally");
KtModifierKeywordToken FINAL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("final");
KtModifierKeywordToken LATEINIT_KEYWORD = KtModifierKeywordToken.softKeywordModifier("lateinit");
KtModifierKeywordToken DATA_KEYWORD = KtModifierKeywordToken.softKeywordModifier("data");
KtModifierKeywordToken INLINE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("inline");
KtModifierKeywordToken NOINLINE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("noinline");
KtModifierKeywordToken TAILREC_KEYWORD = KtModifierKeywordToken.softKeywordModifier("tailrec");
KtModifierKeywordToken EXTERNAL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("external");
KtModifierKeywordToken ANNOTATION_KEYWORD = KtModifierKeywordToken.softKeywordModifier("annotation");
KtModifierKeywordToken CROSSINLINE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("crossinline");
KtModifierKeywordToken OPERATOR_KEYWORD = KtModifierKeywordToken.softKeywordModifier("operator");
KtModifierKeywordToken INFIX_KEYWORD = KtModifierKeywordToken.softKeywordModifier("infix");
KtModifierKeywordToken CONST_KEYWORD = KtModifierKeywordToken.softKeywordModifier("const");
KtModifierKeywordToken SUSPEND_KEYWORD = KtModifierKeywordToken.softKeywordModifier("suspend");
KtModifierKeywordToken HEADER_KEYWORD = KtModifierKeywordToken.softKeywordModifier("header");
KtModifierKeywordToken IMPL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("impl");
this
關(guān)鍵字
this
關(guān)鍵字持有當(dāng)前對象的引用。我們可以使用this
來引用變量或者成員函數(shù)召烂,也可以使用return this
碱工,來返回某個類的引用。
代碼示例
class ThisDemo {
val thisis = "THIS IS"
fun whatIsThis(): ThisDemo {
println(this.thisis) //引用變量
this.howIsThis()// 引用成員函數(shù)
return this // 返回此類的引用
}
fun howIsThis(){
println("HOW IS THIS ?")
}
}
測試代碼
@Test
fun testThisDemo(){
val demo = ThisDemo()
println(demo.whatIsThis())
}
輸出
THIS IS
HOW IS THIS ?
com.easy.kotlin.ThisDemo@475232fc
在類的成員中奏夫,this 指向的是該類的當(dāng)前對象怕篷。
在擴展函數(shù)或者帶接收者的函數(shù)字面值中, this 表示在點左側(cè)傳遞的 接收者參數(shù)酗昼。
代碼示例:
>>> val sum = fun Int.(x:Int):Int = this + x
>>> sum
kotlin.Int.(kotlin.Int) -> kotlin.Int
>>> 1.sum(1)
2
>>> val concat = fun String.(x:Any) = this + x
>>> "abc".concat(123)
abc123
>>> "abc".concat(true)
abctrue
如果 this 沒有限定符廊谓,它指的是最內(nèi)層的包含它的作用域。如果我們想要引用其他作用域中的 this麻削,可以使用 this@label 標(biāo)簽蒸痹。
代碼示例:
class Outer {
val oh = "Oh!"
inner class Inner {
fun m() {
val outer = this@Outer
val inner = this@Inner
val pthis = this
println("outer=" + outer)
println("inner=" + inner)
println("pthis=" + pthis)
println(this@Outer.oh)
val fun1 = hello@ fun String.() {
val d1 = this // fun1 的接收者
println("d1" + d1)
}
val fun2 = { s: String ->
val d2 = this
println("d2=" + d2)
}
"abc".fun1()
fun2
}
}
}
測試代碼:
@Test
fun testThisKeyWord() {
val outer = Outer()
outer.Inner().m()
}
輸出
outer=com.easy.kotlin.Outer@5114e183
inner=com.easy.kotlin.Outer$Inner@5aa8ac7f
pthis=com.easy.kotlin.Outer$Inner@5aa8ac7f
Oh!
d1abc
super 關(guān)鍵字
super關(guān)鍵字持有指向其父類的引用。
代碼示例:
open class Father {
open val firstName = "Chen"
open val lastName = "Jason"
fun ff() {
println("FFF")
}
}
class Son : Father {
override var firstName = super.firstName
override var lastName = "Jack"
constructor(lastName: String) {
this.lastName = lastName
}
fun love() {
super.ff() // 調(diào)用父類方法
println(super.firstName + " " + super.lastName + " Love " + this.firstName + " " + this.lastName)
}
}
測試代碼
@Test
fun testSuperKeyWord() {
val son = Son("Harry")
son.love()
}
輸出
FFF
Chen Jason Love Chen Harry
3.7.3 操作符和操作符的重載
Kotlin 允許我們?yōu)樽约旱念愋吞峁╊A(yù)定義的一組操作符的實現(xiàn)呛哟。這些操作符具有固定的符號表示(如 +
或 *
)和固定的優(yōu)先級叠荠。這些操作符的符號定義如下:
KtSingleValueToken LBRACKET = new KtSingleValueToken("LBRACKET", "[");
KtSingleValueToken RBRACKET = new KtSingleValueToken("RBRACKET", "]");
KtSingleValueToken LBRACE = new KtSingleValueToken("LBRACE", "{");
KtSingleValueToken RBRACE = new KtSingleValueToken("RBRACE", "}");
KtSingleValueToken LPAR = new KtSingleValueToken("LPAR", "(");
KtSingleValueToken RPAR = new KtSingleValueToken("RPAR", ")");
KtSingleValueToken DOT = new KtSingleValueToken("DOT", ".");
KtSingleValueToken PLUSPLUS = new KtSingleValueToken("PLUSPLUS", "++");
KtSingleValueToken MINUSMINUS = new KtSingleValueToken("MINUSMINUS", "--");
KtSingleValueToken MUL = new KtSingleValueToken("MUL", "*");
KtSingleValueToken PLUS = new KtSingleValueToken("PLUS", "+");
KtSingleValueToken MINUS = new KtSingleValueToken("MINUS", "-");
KtSingleValueToken EXCL = new KtSingleValueToken("EXCL", "!");
KtSingleValueToken DIV = new KtSingleValueToken("DIV", "/");
KtSingleValueToken PERC = new KtSingleValueToken("PERC", "%");
KtSingleValueToken LT = new KtSingleValueToken("LT", "<");
KtSingleValueToken GT = new KtSingleValueToken("GT", ">");
KtSingleValueToken LTEQ = new KtSingleValueToken("LTEQ", "<=");
KtSingleValueToken GTEQ = new KtSingleValueToken("GTEQ", ">=");
KtSingleValueToken EQEQEQ = new KtSingleValueToken("EQEQEQ", "===");
KtSingleValueToken ARROW = new KtSingleValueToken("ARROW", "->");
KtSingleValueToken DOUBLE_ARROW = new KtSingleValueToken("DOUBLE_ARROW", "=>");
KtSingleValueToken EXCLEQEQEQ = new KtSingleValueToken("EXCLEQEQEQ", "!==");
KtSingleValueToken EQEQ = new KtSingleValueToken("EQEQ", "==");
KtSingleValueToken EXCLEQ = new KtSingleValueToken("EXCLEQ", "!=");
KtSingleValueToken EXCLEXCL = new KtSingleValueToken("EXCLEXCL", "!!");
KtSingleValueToken ANDAND = new KtSingleValueToken("ANDAND", "&&");
KtSingleValueToken OROR = new KtSingleValueToken("OROR", "||");
KtSingleValueToken SAFE_ACCESS = new KtSingleValueToken("SAFE_ACCESS", "?.");
KtSingleValueToken ELVIS = new KtSingleValueToken("ELVIS", "?:");
KtSingleValueToken QUEST = new KtSingleValueToken("QUEST", "?");
KtSingleValueToken COLONCOLON = new KtSingleValueToken("COLONCOLON", "::");
KtSingleValueToken COLON = new KtSingleValueToken("COLON", ":");
KtSingleValueToken SEMICOLON = new KtSingleValueToken("SEMICOLON", ";");
KtSingleValueToken DOUBLE_SEMICOLON = new KtSingleValueToken("DOUBLE_SEMICOLON", ";;");
KtSingleValueToken RANGE = new KtSingleValueToken("RANGE", "..");
KtSingleValueToken EQ = new KtSingleValueToken("EQ", "=");
KtSingleValueToken MULTEQ = new KtSingleValueToken("MULTEQ", "*=");
KtSingleValueToken DIVEQ = new KtSingleValueToken("DIVEQ", "/=");
KtSingleValueToken PERCEQ = new KtSingleValueToken("PERCEQ", "%=");
KtSingleValueToken PLUSEQ = new KtSingleValueToken("PLUSEQ", "+=");
KtSingleValueToken MINUSEQ = new KtSingleValueToken("MINUSEQ", "-=");
KtKeywordToken NOT_IN = KtKeywordToken.keyword("NOT_IN", "!in");
KtKeywordToken NOT_IS = KtKeywordToken.keyword("NOT_IS", "!is");
KtSingleValueToken HASH = new KtSingleValueToken("HASH", "#");
KtSingleValueToken AT = new KtSingleValueToken("AT", "@");
KtSingleValueToken COMMA = new KtSingleValueToken("COMMA", ",");
3.7.4 操作符優(yōu)先級(Precedence)
優(yōu)先級 | 標(biāo)題 | 符號 |
---|---|---|
最高 | 后綴(Postfix ) |
++ , -- , . , ?. , ?
|
前綴(Prefix) |
- , + , ++ , -- , ! , labelDefinition @
|
|
右手類型運算(Type RHS,right-hand side class type (RHS) ) |
: , as , as?
|
|
乘除取余(Multiplicative) |
* , / , %
|
|
加減(Additive ) |
+ , -
|
|
區(qū)間范圍(Range) | .. |
|
Infix函數(shù) | 例如扫责,給Int 定義擴展 infix fun Int.shl(x: Int): Int {...} ,這樣調(diào)用 1 shl 2 榛鼎,等同于1.shl(2)
|
|
Elvis操作符 | ?: |
|
命名檢查符(Named checks) |
in , !in , is , !is
|
|
比較大小(Comparison) |
< , > , <= , >=
|
|
相等性判斷(Equality) |
== , \!==
|
|
與 (Conjunction) | && |
|
或 (Disjunction) | ll |
|
最低 | 賦值(Assignment) |
= , += , -= , *= , /= , %=
|
注:Markdown表格語法:ll
是||
公给。
為實現(xiàn)這些的操作符借帘,Kotlin為二元操作符左側(cè)的類型和一元操作符的參數(shù)類型,提供了相應(yīng)的函數(shù)或擴展函數(shù)淌铐。
例如在kotlin/core/builtins/native/kotlin/Primitives.kt代碼中肺然,對基本類型Int的操作符的實現(xiàn)代碼如下
public class Int private constructor() : Number(), Comparable<Int> {
...
/**
* Compares this value with the specified value for order.
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
* or a positive number if it's greater than other.
*/
public operator fun compareTo(other: Byte): Int
/**
* Compares this value with the specified value for order.
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
* or a positive number if it's greater than other.
*/
public operator fun compareTo(other: Short): Int
/**
* Compares this value with the specified value for order.
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
* or a positive number if it's greater than other.
*/
public override operator fun compareTo(other: Int): Int
/**
* Compares this value with the specified value for order.
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
* or a positive number if it's greater than other.
*/
public operator fun compareTo(other: Long): Int
/**
* Compares this value with the specified value for order.
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
* or a positive number if it's greater than other.
*/
public operator fun compareTo(other: Float): Int
/**
* Compares this value with the specified value for order.
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
* or a positive number if it's greater than other.
*/
public operator fun compareTo(other: Double): Int
/** Adds the other value to this value. */
public operator fun plus(other: Byte): Int
/** Adds the other value to this value. */
public operator fun plus(other: Short): Int
/** Adds the other value to this value. */
public operator fun plus(other: Int): Int
/** Adds the other value to this value. */
public operator fun plus(other: Long): Long
/** Adds the other value to this value. */
public operator fun plus(other: Float): Float
/** Adds the other value to this value. */
public operator fun plus(other: Double): Double
/** Subtracts the other value from this value. */
public operator fun minus(other: Byte): Int
/** Subtracts the other value from this value. */
public operator fun minus(other: Short): Int
/** Subtracts the other value from this value. */
public operator fun minus(other: Int): Int
/** Subtracts the other value from this value. */
public operator fun minus(other: Long): Long
/** Subtracts the other value from this value. */
public operator fun minus(other: Float): Float
/** Subtracts the other value from this value. */
public operator fun minus(other: Double): Double
/** Multiplies this value by the other value. */
public operator fun times(other: Byte): Int
/** Multiplies this value by the other value. */
public operator fun times(other: Short): Int
/** Multiplies this value by the other value. */
public operator fun times(other: Int): Int
/** Multiplies this value by the other value. */
public operator fun times(other: Long): Long
/** Multiplies this value by the other value. */
public operator fun times(other: Float): Float
/** Multiplies this value by the other value. */
public operator fun times(other: Double): Double
/** Divides this value by the other value. */
public operator fun div(other: Byte): Int
/** Divides this value by the other value. */
public operator fun div(other: Short): Int
/** Divides this value by the other value. */
public operator fun div(other: Int): Int
/** Divides this value by the other value. */
public operator fun div(other: Long): Long
/** Divides this value by the other value. */
public operator fun div(other: Float): Float
/** Divides this value by the other value. */
public operator fun div(other: Double): Double
/** Calculates the remainder of dividing this value by the other value. */
@Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
public operator fun mod(other: Byte): Int
/** Calculates the remainder of dividing this value by the other value. */
@Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
public operator fun mod(other: Short): Int
/** Calculates the remainder of dividing this value by the other value. */
@Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
public operator fun mod(other: Int): Int
/** Calculates the remainder of dividing this value by the other value. */
@Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
public operator fun mod(other: Long): Long
/** Calculates the remainder of dividing this value by the other value. */
@Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
public operator fun mod(other: Float): Float
/** Calculates the remainder of dividing this value by the other value. */
@Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
public operator fun mod(other: Double): Double
/** Calculates the remainder of dividing this value by the other value. */
@SinceKotlin("1.1")
public operator fun rem(other: Byte): Int
/** Calculates the remainder of dividing this value by the other value. */
@SinceKotlin("1.1")
public operator fun rem(other: Short): Int
/** Calculates the remainder of dividing this value by the other value. */
@SinceKotlin("1.1")
public operator fun rem(other: Int): Int
/** Calculates the remainder of dividing this value by the other value. */
@SinceKotlin("1.1")
public operator fun rem(other: Long): Long
/** Calculates the remainder of dividing this value by the other value. */
@SinceKotlin("1.1")
public operator fun rem(other: Float): Float
/** Calculates the remainder of dividing this value by the other value. */
@SinceKotlin("1.1")
public operator fun rem(other: Double): Double
/** Increments this value. */
public operator fun inc(): Int
/** Decrements this value. */
public operator fun dec(): Int
/** Returns this value. */
public operator fun unaryPlus(): Int
/** Returns the negative of this value. */
public operator fun unaryMinus(): Int
/** Creates a range from this value to the specified [other] value. */
public operator fun rangeTo(other: Byte): IntRange
/** Creates a range from this value to the specified [other] value. */
public operator fun rangeTo(other: Short): IntRange
/** Creates a range from this value to the specified [other] value. */
public operator fun rangeTo(other: Int): IntRange
/** Creates a range from this value to the specified [other] value. */
public operator fun rangeTo(other: Long): LongRange
/** Shifts this value left by [bits]. */
public infix fun shl(bitCount: Int): Int
/** Shifts this value right by [bits], filling the leftmost bits with copies of the sign bit. */
public infix fun shr(bitCount: Int): Int
/** Shifts this value right by [bits], filling the leftmost bits with zeros. */
public infix fun ushr(bitCount: Int): Int
/** Performs a bitwise AND operation between the two values. */
public infix fun and(other: Int): Int
/** Performs a bitwise OR operation between the two values. */
public infix fun or(other: Int): Int
/** Performs a bitwise XOR operation between the two values. */
public infix fun xor(other: Int): Int
/** Inverts the bits in this value. */
public fun inv(): Int
public override fun toByte(): Byte
public override fun toChar(): Char
public override fun toShort(): Short
public override fun toInt(): Int
public override fun toLong(): Long
public override fun toFloat(): Float
public override fun toDouble(): Double
}
從源代碼我們可以看出,重載操作符的函數(shù)需要用 operator
修飾符標(biāo)記腿准。中綴操作符的函數(shù)使用infix
修飾符標(biāo)記际起。
3.7.5 一元操作符(unary operation)
前綴操作符
表達(dá)式 | 翻譯為 |
---|---|
+a |
a.unaryPlus() |
-a |
a.unaryMinus() |
!a |
a.not() |
例如,當(dāng)編譯器處理表達(dá)式 +a
時吐葱,它將執(zhí)行以下步驟:
- 確定
a
的類型街望,令其為T
。 - 為接收者
T
查找一個帶有operator
修飾符的無參函數(shù)unaryPlus()
弟跑,即成員函數(shù)或擴展函數(shù)灾前。 - 如果函數(shù)不存在或不明確,則導(dǎo)致編譯錯誤孟辑。
- 如果函數(shù)存在且其返回類型為
R
哎甲,那就表達(dá)式+a
具有類型R
蔫敲。
編譯器對這些操作以及所有其他操作都針對基本類型做了優(yōu)化,不會引入函數(shù)調(diào)用的開銷炭玫。
以下是如何重載一元減運算符的示例:
package com.easy.kotlin
/**
* Created by jack on 2017/6/10.
*/
class OperatorDemo {
}
data class Point(val x: Int, val y: Int)
operator fun Point.unaryMinus() = Point(-x, -y)
測試代碼:
package com.easy.kotlin
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
/**
* Created by jack on 2017/6/10.
*/
@RunWith(JUnit4::class)
class OperatorDemoTest {
@Test
fun testPointUnaryMinus() {
val p = Point(1, 1)
val np = -p
println(np) //Point(x=-1, y=-1)
}
}
遞增和遞減
表達(dá)式 | 翻譯為 |
---|---|
a++ |
a.inc() 返回值是a
|
a-- |
a.dec() 返回值是a
|
++a |
a.inc() 返回值是a+1
|
--a |
a.dec() 返回值是a-1
|
inc()
和 dec()
函數(shù)必須返回一個值奈嘿,它用于賦值給使用 ++
或 --
操作的變量。
編譯器執(zhí)行以下步驟來解析后綴形式的操作符吞加,例如 a++
:
- 確定
a
的類型裙犹,令其為T
。 - 查找一個適用于類型為
T
的接收者的衔憨、帶有operator
修飾符的無參數(shù)函數(shù)inc()
叶圃。 - 檢查函數(shù)的返回類型是
T
的子類型。
計算表達(dá)式的步驟是:
- 把
a
的初始值存儲到臨時存儲a_
中 - 把
a.inc()
結(jié)果賦值給a
- 把
a_
作為表達(dá)式的結(jié)果返回
( a--
同理分析)巫财。
對于前綴形式 ++a
和 --a
解析步驟類似盗似,但是返回值是取的新值來返回:
- 把
a.inc()
結(jié)果賦值給a
- 把
a
的新值a+1
作為表達(dá)式結(jié)果返回
( --a
同理分析)。
3.7.6 二元操作符
算術(shù)運算符
表達(dá)式 | 翻譯為 |
---|---|
a + b |
a.plus(b) |
a - b |
a.minus(b) |
a * b |
a.times(b) |
a / b |
a.div(b) |
a % b |
a.rem(b) 平项、 a.mod(b)
|
a..b |
a.rangeTo(b) |
代碼示例
>>> val a=10
>>> val b=3
>>> a+b
13
>>> a-b
7
>>> a/b
3
>>> a%b
1
>>> a..b
10..3
>>> b..a
3..10
字符串的+
運算符重載
先用代碼舉個例子:
>>> ""+1
1
>>> 1+""
error: none of the following functions can be called with the arguments supplied:
public final operator fun plus(other: Byte): Int defined in kotlin.Int
public final operator fun plus(other: Double): Double defined in kotlin.Int
public final operator fun plus(other: Float): Float defined in kotlin.Int
public final operator fun plus(other: Int): Int defined in kotlin.Int
public final operator fun plus(other: Long): Long defined in kotlin.Int
public final operator fun plus(other: Short): Int defined in kotlin.Int
1+""
^
從上面的示例,我們可以看出悍及,在Kotlin中1+""
是不允許的(這地方闽瓢,相比Scala,寫這樣的Kotlin代碼就顯得不大友好)心赶,只能顯式調(diào)用toString
來相加:
>>> 1.toString()+""
1
自定義重載的 +
運算符
下面我們使用一個計數(shù)類 Counter 重載的 +
運算符來增加index的計數(shù)值扣讼。
代碼示例
data class Counter(var index: Int)
operator fun Counter.plus(increment: Int): Counter {
return Counter(index + increment)
}
測試類
package com.easy.kotlin
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
/**
* Created by jack on 2017/6/10.
*/
@RunWith(JUnit4::class)
class OperatorDemoTest
@Test
fun testCounterIndexPlus() {
val c = Counter(1)
val cplus = c + 10
println(cplus) //Counter(index=11)
}
}
in
操作符
表達(dá)式 | 翻譯為 |
---|---|
a in b |
b.contains(a) |
a !in b |
!b.contains(a) |
索引訪問操作符
表達(dá)式 | 翻譯為 |
---|---|
a[i] |
a.get(i) |
a[i] = b |
a.set(i, b) |
方括號轉(zhuǎn)換為調(diào)用帶有適當(dāng)數(shù)量參數(shù)的 get
和 set
。
調(diào)用操作符
表達(dá)式 | 翻譯為 |
---|---|
a() |
a.invoke() |
a(i) |
a.invoke(i) |
圓括號轉(zhuǎn)換為調(diào)用帶有適當(dāng)數(shù)量參數(shù)的 invoke
缨叫。
計算并賦值
表達(dá)式 | 翻譯為 |
---|---|
a += b |
a.plusAssign(b) |
a -= b |
a.minusAssign(b) |
a *= b |
a.timesAssign(b) |
a /= b |
a.divAssign(b) |
a %= b |
a.modAssign(b) |
對于賦值操作椭符,例如 a += b
,編譯器會試著生成 a = a + b
的代碼(這里包含類型檢查:a + b
的類型必須是 a
的子類型)耻姥。
相等與不等操作符
Kotlin 中有兩種類型的相等性:
- 引用相等
===
!==
(兩個引用指向同一對象) - 結(jié)構(gòu)相等
==
!=
( 使用equals()
判斷)
表達(dá)式 | 翻譯為 |
---|---|
a == b |
a?.equals(b) ?: (b === null) |
a != b |
!(a?.equals(b) ?: (b === null)) |
這個 ==
操作符有些特殊:它被翻譯成一個復(fù)雜的表達(dá)式销钝,用于篩選 null
值。
意思是:如果 a 不是 null 則調(diào)用 equals(Any?)
函數(shù)并返回其值琐簇;否則(即 a === null
)就計算 b === null
的值并返回蒸健。
當(dāng)與 null 顯式比較時,a == null
會被自動轉(zhuǎn)換為 a=== null
注意:===
和 !==
不可重載婉商。
Elvis 操作符 ?:
在Kotin中似忧,Elvis操作符特定是跟null比較。也就是說
y = x?:0
等價于
val y = if(x!==null) x else 0
主要用來作null
安全性檢查丈秩。
Elvis操作符 ?:
是一個二元運算符盯捌,如果第一個操作數(shù)為真,則返回第一個操作數(shù)蘑秽,否則將計算并返回其第二個操作數(shù)饺著。它是三元條件運算符的變體箫攀。命名靈感來自貓王的發(fā)型風(fēng)格。
Kotlin中沒有這樣的三元運算符 true?1:0
瓶籽,取而代之的是if(true) 1 else 0
匠童。而Elvis操作符算是精簡版的三元運算符。
我們在Java中使用的三元運算符的語法塑顺,你通常要重復(fù)變量兩次汤求, 示例:
String name = "Elvis Presley";
String displayName = (name != null) ? name : "Unknown";
取而代之,你可以使用Elvis操作符严拒。
String name = "Elvis Presley";
String displayName = name?:"Unknown"
我們可以看出扬绪,用Elvis操作符(?:)可以把帶有默認(rèn)值的if/else結(jié)構(gòu)寫的及其短小。用Elvis操作符不用檢查null(避免了NullPointerException
)裤唠,也不用重復(fù)變量挤牛。
這個Elvis操作符功能在Spring 表達(dá)式語言 (SpEL)中提供。
在Kotlin中當(dāng)然就沒有理由不支持這個特性种蘸。
代碼示例:
>>> val x = null
>>> val y = x?:0
>>> y
0
>>> val x = false
>>> val y = x?:0
>>> y
false
>>> val x = ""
>>> val y = x?:0
>>> y
>>> val x = "abc"
>>> val y = x?:0
>>> y
abc
比較操作符
表達(dá)式 | 翻譯為 |
---|---|
a > b |
a.compareTo(b) > 0 |
a < b |
a.compareTo(b) < 0 |
a >= b |
a.compareTo(b) >= 0 |
a <= b |
a.compareTo(b) <= 0 |
所有的比較都轉(zhuǎn)換為對 compareTo
的調(diào)用墓赴,這個函數(shù)需要返回 Int
值
用infix函數(shù)自定義中綴操作符
我們可以通過自定義infix函數(shù)來實現(xiàn)中綴操作符。
代碼示例
data class Person(val name: String, val age: Int)
infix fun Person.grow(years: Int): Person {
return Person(name, age + years)
}
測試代碼
package com.easy.kotlin
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
/**
* Created by jack on 2017/6/11.
*/
@RunWith(JUnit4::class)
class InfixFunctionDemoTest {
@Test fun testInfixFuntion() {
val person = Person("Jack", 20)
println(person.grow(2))
println(person grow 2)
}
}
輸出
Person(name=Jack, age=22)
Person(name=Jack, age=22)
3.8 函數(shù)擴展和屬性擴展(Extensions)
Kotlin 支持 擴展函數(shù) 和 擴展屬性航瞭。其能夠擴展一個類的新功能而無需繼承該類或使用像裝飾者這樣的設(shè)計模式等诫硕。
大多數(shù)時候我們在頂層定義擴展,即直接在包里:
package com.easy.kotlin
/**
* Created by jack on 2017/6/11.
*/
val <T> List<T>.lastIndex: Int get() = size - 1
fun String.notEmpty(): Boolean {
return !this.isEmpty()
}
這樣我們就可以在整個包里使用這些擴展刊侯。
要使用其他包的擴展章办,我們需要在調(diào)用方導(dǎo)入它:
package com.example.usage
import foo.bar.goo // 導(dǎo)入所有名為“goo”的擴展
// 或者
import foo.bar.* // 從“foo.bar”導(dǎo)入一切
fun usage(baz: Baz) {
baz.goo()
}
3.8.1 擴展函數(shù)
聲明一個擴展函數(shù),我們需要用被擴展的類型來作為前綴滨彻。
比如說藕届,我們不喜歡類似下面的雙重否定式的邏輯判斷(繞腦子):
>>> !"123".isEmpty()
true
我們就可以為String
類型擴展一個notEmpty()
函數(shù):
>>> fun String.notEmpty():Boolean{
... return !this.isEmpty()
... }
>>> "".notEmpty()
false
>>> "123".notEmpty()
true
下面代碼為 MutableList<Int>
添加一個swap
函數(shù):
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // this對應(yīng)該列表
this[index1] = this[index2]
this[index2] = tmp
}
這個 this
關(guān)鍵字在擴展函數(shù)內(nèi)部對應(yīng)到接收者對象(傳過來的在點.
符號前的對象) 現(xiàn)在,我們對任意 MutableList<Int>
調(diào)用該函數(shù)了亭饵。
當(dāng)然休偶,這個函數(shù)對任何 MutableList<T>
起作用,我們可以泛化它:
fun <T> MutableList<T>.mswap(index1: Int, index2: Int) {
val tmp = this[index1] // “this”對應(yīng)該列表
this[index1] = this[index2]
this[index2] = tmp
}
為了在接收者類型表達(dá)式中使用泛型冬骚,我們要在函數(shù)名前聲明泛型參數(shù)椅贱。
完整代碼示例
package com.easy.kotlin
/**
- Created by jack on 2017/6/11.
*/
val <T> List<T>.lastIndex: Int get() = size - 1
fun String.notEmpty(): Boolean {
return !this.isEmpty()
}
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // this對應(yīng)該列表m
this[index1] = this[index2]
this[index2] = tmp
}
fun <T> MutableList<T>.mswap(index1: Int, index2: Int) {
val tmp = this[index1] // “this”對應(yīng)該列表
this[index1] = this[index2]
this[index2] = tmp
}
class ExtensionsDemo {
fun useExtensions() {
val a = "abc"
println(a.notEmpty())//true
val mList = mutableListOf<Int>(1, 2, 3, 4, 5)
println("Before Swap:")
println(mList)//[1, 2, 3, 4, 5]
mList.swap(0, mList.size - 1)
println("After Swap:")
println(mList)//[5, 2, 3, 4, 1]
val mmList = mutableListOf<String>("a12", "b34", "c56", "d78")
println("Before Swap:")
println(mmList)//[a12, b34, c56, d78]
mmList.mswap(1, 2)
println("After Swap:")
println(mmList)//[a12, c56, b34, d78]
val mmmList = mutableListOf<Int>(100, 200, 300, 400, 500)
println("Before Swap:")
println(mmmList)
mmmList.mswap(0, mmmList.lastIndex)
println("After Swap:")
println(mmmList)
}
class Inner {
fun useExtensions() {
val mmmList = mutableListOf<Int>(100, 200, 300, 400, 500)
println(mmmList.lastIndex)
}
}
}
測試代碼
package com.easy.kotlin
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
/**
- Created by jack on 2017/6/11.
*/
@RunWith(JUnit4::class)
class ExtensionsDemoTest {
@Test fun testExtensionsDemo() {
val demo = ExtensionsDemo()
demo.useExtensions()
}
}
擴展不是真正的修改他們所擴展的類。我們定義一個擴展只冻,其實并沒有在一個類中插入新函數(shù)庇麦,僅僅是通過該類型的變量,用點.表達(dá)式去調(diào)用這個新函數(shù)喜德。
3.8.2 擴展屬性
和函數(shù)類似山橄,Kotlin 支持?jǐn)U展屬性:
val <T> List<T>.lastIndex: Int
get() = size - 1
注意:由于擴展沒有實際的將成員插入類中,因此對擴展的屬性來說舍悯,它的行為只能由顯式提供的 getters/setters 定義航棱。
代碼示例:
package com.easy.kotlin
/**
* Created by jack on 2017/6/11.
*/
val <T> List<T>.lastIndex: Int get() = size - 1
我們可以直接使用包com.easy.kotlin
中擴展的屬性lastIndex
:
3.9 空指針安全(Null-safety)
我們寫代碼的時候知道睡雇,在Java中NPE(NullPointerExceptions)是一件成程序員幾近崩潰的事情。很多時候饮醇,雖然費盡體力腦力它抱,仍然防不勝防。
以前朴艰,當(dāng)我們不確定一個DTO類中的字段是否已初始化時观蓄,可以使用@Nullable和@NotNull注解來聲明,但功能很有限祠墅。
現(xiàn)在好了侮穿,Kotlin在編譯器級別,把你之前在Java中需要寫的null check代碼完成了毁嗦。
但是亲茅,當(dāng)我們的代碼
- 顯式調(diào)用
throw NullPointerException()
- 使用了
!!
操作符 - 調(diào)用的外部 Java 代碼有NPE
- 對于初始化,有一些數(shù)據(jù)不一致(如一個未初始化的
this
用于構(gòu)造函數(shù)的某個地方)
也可能會發(fā)生NPE狗准。
在Kotlin中null
等同于空指針克锣。我們來通過代碼來看一下null
的有趣的特性:
首先,一個非空引用不能直接賦值為null
:
>>> var a="abc"
>>> a=null
error: null can not be a value of a non-null type String
a=null
^
>>> var one=1
>>> one=null
error: null can not be a value of a non-null type Int
one=null
^
>>> var arrayInts = intArrayOf(1,2,3)
>>> arrayInts=null
error: null can not be a value of a non-null type IntArray
arrayInts=null
^
這樣腔长,我們就可以放心地調(diào)用 a 的方法或者訪問它的屬性娶耍,不會導(dǎo)致 NPE:
>>> val a="abc"
>>> a.length
3
如果要允許為空,我們可以在變量的類型后面加個問號?聲明一個變量為可空的:
>>> var a:String?="abc"
>>> a=null
>>> var one:Int?=1
>>> one=null
>>> var arrayInts:IntArray?=intArrayOf(1,2,3)
>>> arrayInts=null
>>> arrayInts
null
如果我們聲明了一個可空String?類型變量na 饼酿,然后直接調(diào)用length屬性,這將是不安全的胚膊。編譯器會直接報錯:
>>> var na:String?="abc"
>>> na=null
>>> na.length
error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
na.length
我們使用安全調(diào)用?. 和 非空斷言調(diào)用 !!.
>>> na?.length
null
>>> na!!.length
kotlin.KotlinNullPointerException
我們可以看出故俐,代碼返回了null 和 kotlin.KotlinNullPointerException。
安全調(diào)用在鏈?zhǔn)秸{(diào)用中很有用紊婉。在調(diào)用鏈中如果任意一個屬性(環(huán)節(jié))為空药版,這個鏈?zhǔn)秸{(diào)用就會安全返回 null。
如果要只對非空值執(zhí)行某個操作喻犁,安全調(diào)用操作符可以與 let (以調(diào)用者的值作為參數(shù)來執(zhí)行指定的函數(shù)塊槽片,并返回其結(jié)果)一起使用:
>>> val listWithNulls: List<String?> = listOf("A", "B",null)
>>> listWithNulls
[A, B, null]
>>> listWithNulls.forEach{
... it?.let{println(it)}
... }
A
B
本章小結(jié)
本章我們學(xué)習(xí)了Kotlin語言的基本詞匯(關(guān)鍵字、標(biāo)識符等)肢础、句子(流程控制还栓、表達(dá)式、操作符等)和一些基礎(chǔ)語法传轰。同時剩盒,學(xué)習(xí)了空指針安全、擴展函數(shù)與擴展屬性等的語言特性慨蛙。
我們將在下一章節(jié)中介紹Kotlin的基本類型和類型系統(tǒng)辽聊。