コード例(2)


abstract type AbstractTime

In [1]:
abstract type AbstractTime end
In [2]:
function gethour end
function getminute end
function getsecond end
Out[2]:
getsecond (generic function with 0 methods)

Note:
引数列なし(() さえもなし)で記述した関数定義は所謂『関数宣言』のような役割をしますっ


show

In [3]:
using Printf

function Base.show(io::IO, time::AbstractTime)
    @printf(io, "%02d:%02d:%02d",
            gethour(time),
            getminute(time),
            getsecond(time))
end

Note:
Base.show() を多重定義すると、REPL でインスタンスを参照したときなどにその情報が表示されます。
他言語の .toString() とか .__str__() に類似(同一ではない)


struct MyTime

In [4]:
struct MyTime <: AbstractTime
    hour::Integer
    minute::Integer
    second::Integer
end
In [5]:
gethour(time::MyTime) = time.hour
getminute(time::MyTime) = time.minute
getsecond(time::MyTime) = time.second
Out[5]:
getsecond (generic function with 1 method)

Note:
《関数名》(引数列) = 《式》 と言う書式でも関数定義が出来ます。


MyTime(12, 34, 56)

In [6]:
MyTime(12, 34, 56)
Out[6]:
12:34:56

Note:
MyTime 型で show() を多重定義していませんが、その supertype である AbstractTime 型では定義されているので、そちらが呼ばれましたっ
後その中で参照されている getxxxx(time) は、新しく定義した関数が呼ばれていますっ


struct MyTime2

In [7]:
struct MyTime2 <: AbstractTime
    seconds::Integer
end

Note:
MyTime2 型は、時刻として午前0時からの秒数だけを保持する型。

In [8]:
gethour(time::MyTime2) = time.seconds ÷ 3600
getminute(time::MyTime2) = time.seconds ÷ 60 % 60
getsecond(time::MyTime2) = time.seconds % 60
Out[8]:
getsecond (generic function with 2 methods)

MyTime2(10000)

In [9]:
MyTime2(10000)  # 午前0時の10000秒後は 2:46:40
Out[9]:
02:46:40

Note: MyTime2 型も普通に show() できているのは先ほどと同じ理由っ
その中で参照されている getxxxx(time)MyTime2 型に合った関数が呼ばれていますっ


演習

In [ ]:
function Base.:+(time::AbstractTime, sec::Integer)
    # TODO: 実装してみましょう!
end
# 必要なら他の関数も定義/多重定義してもOK!
In [ ]:
MyTime1(12, 34, 56) + 7890
# => 14:46:26
In [ ]:
MyTime2(10000) + 1234
# => 03:07:14

Point

  • 多重ディスパッチ設計 ≒ インターフェース設計
  • 型継承(subtyping)を理解すると多重ディスパッチがもっと面白くなる!

Note:
次回は型システムについて話したいですっ