式指向プログラミング
平たく言えば、式は値を返すことができるステートメントです。
1 // 单纯的字面量表达式,值为1
-1 // 增加前缀操作符,值为-1
1+1 // 加法操作符,返回2
listOf(1,2,3) // 列表表达式
"kotlin".length // 值为6
これらは非常に明白な表現です。 Kotlin のより複雑な式の例を次に示します。
{
x: Int -> x + 1} // Lambda 表达式,类型为 (Int) -> Int
fun(x: Int) {
println(x) } // 匿名函数表达式,类型为 (Int) -> Unit
if (x > 1) x else 1 // if—else表达式,类型为 Int,假设 x 已赋值
式はステートメントより安全です
void ifStatement(Boolean flag) {
String a = null;
if (flag) {
a = "dive into kotlin";
}
System.out.println(a.toUpperCase());
}
Java では、if
は式ではなくステートメントであるため、変数 a
をここで宣言する必要があります。このコードの潜在的な問題は次のとおりです。 a
は、 if
ステートメントの外側で宣言し、 条件を前提として null
に初期化する必要があります。が常に である場合、プログラムは実行時にエラーを報告しません。そうでない場合は、(コンパイルが成功した場合でも) 実行時に null ポインター例外がスローされます。それが副作用です。 flag
true
次の Kotlin バージョンでは、if
を式として使用してもこの問題は発生しません:
fun ifExpression(flag: Boolean) {
val a = if (flag) "dive into Kotlin" else ""
println(a.toUpperCase())
}
if
が式として使用される場合、 else
分岐も考慮する必要があります。式には型情報があり、最終的には式に型情報があるため、これは理解しやすいです。その A タイプは、 if
、 else
複数のブランチ タイプと同じタイプまたは共通の親タイプです。式ベースのソリューションによって副作用が完全に排除され、プログラムがより安全になっていることがわかります。 Java 関数とは異なり、Kotlin のすべての関数呼び出しも式です。
ユニットタイプ: 関数呼び出しを式にする
Java の関数がすべての式ではないのはなぜですか? 特殊なケースがあるためvoid
、void
関数には戻り値の型がないため、数えることはできません 式を作成します。
では、なぜ Kotlin は Unit
を導入するのでしょうか?大きな理由は、関数型プログラミングが組み合わせ、特に多くの高階関数に焦点を当てており、これらの関数はソース コードに実装するときにジェネリックスを使用して実装されるためです。ただしvoid
ジェネリックが関与する場合には問題が発生します。
複合式: 表現力の向上
ステートメントと比較すると、式は自己完結型になる傾向があり、コンテキストとの状態の共有や相互依存を避けるため、分離性が優れていると言えます。。分離とは副作用を排除することを意味し、式を使用してロジックをより安全に記述することができます。さらに、式はより表現力豊かになることがよくあります。
典型的な例は、式を組み合わせるのが簡単です。各式には値があり、それ自体の一部として別の式を構成することもできるため、複合式を作成できます。
val res: Int? = try {
if (result.success) {
jsonDecode(result.response)
} else null
} catch (e: JsonDecodeException) {
null
}
このプログラムは、HTTP 応答結果を取得し、json
をデコードして、最後に res
変数に割り当てるプロセスを記述します。これは、Kotlin が複数の式を組み合わせる機能をどのように活用しているかを示しています。
try
も Kotlin の式です。try/catch/finally
構文の戻り値の型は、try
またはcatch
部分。finally
影響はありません。- Kotlin では、
if-else
は従来の三項演算子を大幅に置き換えます。文法上の単語の数は増えますが、概念が減り、読みやすくなります。 if-else
の戻り値はtry
部分の戻り値であり、res
の最終値はtry
またはcatch
部分的な決定。
Kotlin の「?:」
Kotlin は三項演算子を使用しませんが、非常に似た構文「?:
」を持っています。ここでは疑問符とコロンを一緒に使用する必要があることに注意してください。これは Elvis 演算子、または null< と呼ばれます。 /span> 演算子を理解することができます: Elvis」を使用して null 許容型の変数を、空のケース。次の例を通して、?
」を使用して型の null 可能性を示すことができるため、「 合体演算子。 Kotlin では、「?:
val maybelnt: Int? = null
maybelnt ?: 1 // 1
Enum クラスと when 式
列挙型はクラスです
Kotlin では、列挙は列挙クラスを通じて実装されます。
enum class Day {
MON, TUE, WED, THU, FRI, SAT, SUN
}
Java と比較すると、記述上のキーワードが 1 つだけ多いcalss
ですが、Java の列挙とは異なり、型であるため、構築パラメータを持つことができ、追加のプロパティとメソッドを定義できます。 。
enum class DayOfWeek(val day: Int) {
MON(1),
TUE(2),
WED(3),
THU(4),
FRI(5),
SAT(6),
SUN(7);
// 如果以下有额外的方法或属性定义,则必须强制加上分号
fun getDayNumber(): Int {
return day
}
}
if-else の代わりに when を使用する
fun schedule(sunny: Boolean, day: Day) = when (day) {
Day.SAT -> basketball()
Day.SUN -> fishing()
Day.FRI -> appointment()
else -> when {
sunny -> library()
else -> study()
}
}
when
式の具体的な構文は次のとおりです。
- 1) 完全な
when
式はswitch
ステートメントに似ており、when
キーワードで始まり、curly を使用します。括弧 複数の論理分岐が含まれており、それぞれが->
で接続されており、switch
のbreak
は必要ありません (これは本当に面倒なキーワードです)。すべての一致が完了するまで上から下に一致します。完了しない場合は、 のelse
分岐のロジックが実行されます。 9> ;switch
default
- 2) 各論理分岐には戻り値があり、最終的に
when
式全体の戻り値の型は、すべての分岐で同じ戻り値の型、または共通の親の型になります。 - 3)
when
キーワードのパラメータは、上記のコードの subwhen
式のように省略できます (ただし、この場合は a>->
左側のものはブール値を返す必要があります。そうでない場合、コンパイルでエラーが報告されます) - 4) 式は組み合わせることができるため、これは式の組み合わせの典型的な
when
例です。 Java ではこのような長い式はほとんど見られませんが、Kotlin では非常に一般的です。
when
式をより柔軟な方法で使用して、深くネストされた問題を解決することもできます。
fun schedule(sunny: Boolean, day: Day) = when {
day == Day.SAT -> basketball()
day == Day.SUN -> fishing()
day == Day.FRI -> appointment()
sunny -> library()
else -> study()
}
ここでも、when()
のパラメータが省略されている場合、各分岐の左側は Boolean
型を返す式である必要があります。
for ループと範囲式
for (i in 1..10) println(i)
これは次の記述と同等です。
for (i: Int in 1..10) {
println(i)
}
実際、イテレータを提供する構造は、次のような for-in
ステートメントを使用して反復できます。
for (c in array) {
println(c)
}
さらに、withIndex
メソッドを呼び出して、キーと値のタプルを提供することもできます。< /span>
for ((index, value) in array.withlndex()) {
println("the element at $index is $value")
}
範囲式
Kotlin 公式 Web サイトでは、Range
式は rangeTo
関数を通じて実装され、「..
」演算子によって構成されます。特定の型のオブジェクト。この型は、整数の基本型に加えて、 java.lang.Comparable
インターフェイスを実装する必要があります。
たとえば、String
クラスは Comparable
インターフェイスを実装しているため、文字列値を比較できるため、次のような文字列 Interval を作成できます。として:
"abc".."xyz"
さらに、整数for
をループする場合、Kotlin はstep
反復 ステップ サイズを定義する関数:
for (i in 1..10 step 2) {
print(i)
}
>>> 13579
逆の順序:
for (i in 10 downTo 1 step 2) {
// 通过 downTo,而不是 10..1
print(i)
}
>>> 108642
さらに、半開間隔を実装するuntil
関数もあります。
for (i in 1 until 10) {
print(i)
}
>>> 123456789 // 并不包含 10
メンバーシップを確認するために使用します
Kotlin では、in
を使用して、要素が範囲またはセットのメンバーであるかどうかを確認できます。
"a" in listOf("b", "c")
>>> false
in
の前に感嘆符を追加すると、逆の結果は次のようになります。
"a" !in listOf("b", "c")
>>> true
等号と不等号に加えて、in
を範囲式と組み合わせて、より多くの意味を表現することもできます。
"kot" in "abc".."xyz"
>>> true
上記のコードは次と同等です。
"kot" >= "abc" && "kot" <= "xyz"
中置式
infix 関数の表現形式は非常に単純で、次のように理解できます。
A 中缀方法 B
infix 関数を定義したい場合は、次の条件を満たしている必要があります。
- infix 関数は、特定の型の拡張関数またはメンバー メソッドである必要があります。
- この中置関数にはパラメーターを 1 つだけ指定できます。
- 中置関数のパラメータにはデフォルト値を設定できません (ただし、Kotlin の関数パラメータはデフォルト値をサポートしています)。そうしないと、上記の形式の B が欠落し、中置式のセマンティクスに影響します。損害を与える;
- パラメータの数を常に 1 に保つ必要があるため、このパラメータを可変個引数パラメータにすることはできません。
Kotlin 標準ライブラリの中置式を使用して設計された to
メソッドを見てみましょう。これはジェネリックを通じて実装されたメソッドであり、Pair
。
infix fun <A, B> A.to(that: B): Pair<A, B>
to
は Pair
のキーと値のペアの構造データを返すため、よくそれを map
と比較します。一緒に。例:
mapOf(
1 to "one",
2 to "two",
3 to "three"
)
中置式をカスタマイズします。
class Person {
infix fun called(name: String) {
println("My name is $name.")
}
}
fun main() {
val p = Person()
p called "Shaw" // 输出:My name is Shaw.
}
これは従来の方法と呼ぶこともできます。
p.called("Shaw")