クラス定義
class Rational(val numerator: Int,
val denominator: Int)
// 使い方
fun main(args: Array) {
val half = Rational(1, 2)
println(half.denominator) // 2
}
Slide 11
Slide 11 text
クラス定義
class Rational(val numerator: Int,
val denominator: Int)
// 使い方
fun main(args: Array) {
val half = Rational(1, 2)
println(half.denominator) // 2
}
クラス名
Slide 12
Slide 12 text
クラス定義
class Rational(val numerator: Int,
val denominator: Int)
// 使い方
fun main(args: Array) {
val half = Rational(1, 2)
println(half.denominator) // 2
}
プライマリコンストラクタ
Slide 13
Slide 13 text
クラス定義
class Rational(val numerator: Int,
val denominator: Int)
// 使い方
fun main(args: Array) {
val half = Rational(1, 2)
println(half.denominator) // 2
}
プロパティ
Slide 14
Slide 14 text
クラス定義
class Rational(val numerator: Int,
val denominator: Int)
// 使い方
fun main(args: Array) {
val half = Rational(1, 2)
println(half.denominator) // 2
}
インスタンス生成
Slide 15
Slide 15 text
クラス定義
class Rational(val numerator: Int,
val denominator: Int)
// 使い方
fun main(args: Array) {
val half = Rational(1, 2)
println(half.denominator) // 2
} プロパティにアクセス:
Javaで言うフィールドとアクセサが一緒になったようなもの
Slide 16
Slide 16 text
ちなみにJavaだと
public final class Rational {
private final int numerator;
private final int denominator;
public Rational(int numerator, int denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
public int getNumerator() { return numerator; }
public int getDenominator() { return denominator; }
}
Slide 17
Slide 17 text
メソッドtoStringをオーバライド
class Rational(val numerator: Int,
val denominator: Int) {
override fun toString()
= "${numerator}/${denominator}"
}
Slide 18
Slide 18 text
メソッドtoStringをオーバライド
class Rational(val numerator: Int,
val denominator: Int) {
override fun toString(): String
= "${numerator}/${denominator}"
}
オーバライドに必須
Slide 19
Slide 19 text
メソッドtoStringをオーバライド
class Rational(val numerator: Int,
val denominator: Int) {
override fun toString(): String
= "${numerator}/${denominator}"
} イコールで式を結びつける
Slide 20
Slide 20 text
メソッドtoStringをオーバライド
class Rational(val numerator: Int,
val denominator: Int) {
override fun toString(): String
= "${numerator}/${denominator}"
} 式が評価された文字列内に展開される
= String Templates
非公開メソッド
class Rational(val numerator: Int,
val denominator: Int) {
...
private fun gcd(x: Int, y: Int): Int =
if(y == 0) x
else gcd(y, x % b)
}
xとyの最大公約数を返すメソッド
Slide 29
Slide 29 text
非公開メソッド
class Rational(val numerator: Int,
val denominator: Int) {
...
private fun gcd(x: Int, y: Int): Int =
if(y == 0) x
else gcd(y, x % y)
} if-elseは式(値を返す)
Slide 30
Slide 30 text
非公開メソッド
class Rational(val numerator: Int,
val denominator: Int) {
...
tailrec private fun gcd(x: Int, y: Int): Int =
if(y == 0) x
else gcd(y, x % y)
} 末尾再帰なので、最適化可能
Slide 31
Slide 31 text
非公開プロパティ
class Rational(n: Int, d: Int) {
init { require(d != 0, {"ゼロはダメ"}) }
private val g: Int = gcd(n, d)
val numerator: Int = n / g
val denominator: Int = d / g
...
}
Slide 32
Slide 32 text
非公開プロパティ
class Rational(n: Int, d: Int) {
init { require(d != 0, {"ゼロはダメ"}) }
private val g: Int = gcd(n, d)
val numerator: Int = n / g
val denominator: Int = d / g
...
}
コンストラクタ引数(プロパティでない)
Slide 33
Slide 33 text
非公開プロパティ
class Rational(n: Int, d: Int) {
init { require(d != 0, {"ゼロはダメ"}) }
private val g: Int = gcd(n, d)
val numerator: Int = n / g
val denominator: Int = d / g
...
}
非公開プロパティ
Slide 34
Slide 34 text
非公開プロパティ
class Rational(n: Int, d: Int) {
init { require(d != 0, {"ゼロはダメ"}) }
private val g: Int = gcd(n, d)
val numerator: Int = n / g
val denominator: Int = d / g
...
}
公開プロパティ
デフォルト引数
abstract class Node {
companion object {
val nil: Node = AbsentNode
fun of(value: T, next: Node = nil) =
PresentNode(value, next)
}
...
}
呼び出し時に引数を省略すると
デフォルト値が使用される
Slide 66
Slide 66 text
通常の抽象クラスは見える人なら継承OK
abstract class Node {...}
class PresentNode(...): Node() {...}
object AbsentNode: Node() {...}
class MyNode: Node() {...}
Slide 67
Slide 67 text
通常の抽象クラスは見える人なら継承OK
abstract class Node {...}
class PresentNode(...): Node() {...}
object AbsentNode: Node() {...}
class MyNode: Node() {...}
今回つくったやつ
Slide 68
Slide 68 text
abstract class Node {...}
class PresentNode(...): Node() {...}
object AbsentNode: Node() {...}
class MyNode: Node() {...}
通常の抽象クラスは見える人なら継承OK
第3者が継承させることができる。でも都合が悪い
Slide 69
Slide 69 text
シールドクラスで継承を制限
sealed class Node { ...
class PresentNode(...): Node() {...}
object AbsentNode: Node() {...}
}
class MyNode: Node() {...}
Slide 70
Slide 70 text
シールドクラスで継承を制限
sealed class Node { ...
class PresentNode(...): Node() {...}
object AbsentNode: Node() {...}
}
class MyNode: Node() {...}
↓この人はもはや継承できない(コンパイルエラー)
注: ver1.1では、シールドクラスの継承可能な範囲が
その内部クラスから同一ファイル内へと緩和される。
Slide 71
Slide 71 text
ノード数プロパティ size
sealed class Node { ...
val size: Int
get() {
tailrec fun go(node: Node, acc: Int): Int =
when(node) {
is AbsentNode -> acc
is PresentNode -> go(node.next, acc + 1)
}
return go(this, 0)
}
}
Slide 72
Slide 72 text
ノード数プロパティ size
sealed class Node { ...
val size: Int
get() {
tailrec fun go(node: Node, acc: Int): Int =
when(node) {
is AbsentNode -> acc
is PresentNode -> go(node.next, acc + 1)
}
return go(this, 0)
}
}
プロパティ size
内部フィールドを持たず、カスタム getterを提供
Slide 73
Slide 73 text
ノード数プロパティ size
sealed class Node { ...
val size: Int
get() {
tailrec fun go(node: Node, acc: Int): Int =
when(node) {
is AbsentNode -> acc
is PresentNode -> go(node.next, acc + 1)
}
return go(this, 0)
}
}
再帰呼び出しでノード数を計算
Slide 74
Slide 74 text
ノード数プロパティ size
sealed class Node { ...
val size: Int
get() {
tailrec fun go(node: Node, acc: Int): Int =
when(node) {
is AbsentNode -> acc
is PresentNode -> go(node.next, acc + 1)
}
return go(this, 0)
}
}
when式=switchの強い版
分岐の網羅が必須
Slide 75
Slide 75 text
委譲プロパティによる遅延初期化
sealed class Node { ...
val size: Int by lazy {
tailrec fun go(node: Node, acc: Int): Int =
when(node) {
is AbsentNode -> acc
is PresentNode -> go(node.next, acc + 1)
}
go(this, 0)
}
}
Slide 76
Slide 76 text
委譲プロパティによる遅延初期化
sealed class Node { ...
val size: Int by lazy {
tailrec fun go(node: Node, acc: Int): Int =
when(node) {
is AbsentNode -> acc
is PresentNode -> go(node.next, acc + 1)
}
go(this, 0)
}
}
プロパティアクセスを
byの後に続くオブジェクトに委譲
Slide 77
Slide 77 text
委譲プロパティによる遅延初期化
sealed class Node { ...
val size: Int by lazy {
tailrec fun go(node: Node, acc: Int): Int =
when(node) {
is AbsentNode -> acc
is PresentNode -> go(node.next, acc + 1)
}
go(this, 0)
}
}
標準関数 lazy
委譲される遅延初期化用オブジェクト
を生成する
Slide 78
Slide 78 text
委譲プロパティによる遅延初期化
sealed class Node { ...
val size: Int by lazy {
tailrec fun go(node: Node, acc: Int): Int =
when(node) {
is AbsentNode -> acc
is PresentNode -> go(node.next, acc + 1)
}
go(this, 0)
}
}
lazyの引数としてのラムダ式