R5クラスを利用してクラスを実装する
Rでクラスを実装するには3つの方法がある。
- S3オブジェクト
- S4オブジェクト
- R5オブジェクト
世に出回っている多くのクラスはS3で実装されているようだが(自分の見た限りだと)、S3は「インスタンス生成時に型エラーを出さない」という致命的な欠陥がある。(と、いうより設計思想だけど)
なので、S3は「負の遺産」だとぼくは思っていて、型チェックのあるS4かR5に切り替えるべきだとぼくは思う。
S4は本格的な「オブジェクト指向の〜」とか説明されているが、どこらへんが「本格的なオブジェクト指向」なのかいまいちわからない。
よっぽどR5オブジェクトの方がオブジェクト指向に近い気がする。(基本的な概念は Javaと同じように考えてもよさそう)
そんなわけでR5クラスの練習をしてみた。
R5クラス定義の記法
みんなのPython p244にある、「体積を求める」クラスをR5で書いてみた。
R5クラスを定義するには
クラス名 <- setRefClass( Class = "クラス名", fields = list(クラス変数名 = "型"), methods = list( function{ メソッドの処理内容 } ) )
の記法で Classとfieldsとmethodsを定義する。
ここで注意なのが、<-
は使ってはダメっぽいってところ。
Class <- "クラス名", fields <- list(), methods <- list()
とか記述しちゃうとR特有のFuxxking Shxxtなエラーが発生するので、要注意
以下にエラー FUN(X[[1L]], ...) : 'contains' 引数は上位クラスの名前であるべきです: クラス “function” の要素を得ました
実際に記述してみる。
Prism <- setRefClass( Class = "Prism", fields = list( width = "numeric", # 左辺に型を記述する height = "numeric", depth = "numeric", v = "numeric" ), methods = list( CalcContent = function(){ v <<- width * height * depth # アトリビュートへの代入は二重の演算子を使う }, PrintResult = function(){ print(v) } ) )
インスタンスの生成
content_instance1 <- Prism$new() # new methodでインスタンスの生成ができるけど・・・このやり方は非推奨らしい content_instance1$depth <- "hoge" # 一応、宣言した型と違うものを代入したら、型エラーが出る
## Error: invalid assignment for reference class field 'depth', should be ## from class "numeric" or a subclass (was class "character")
content_instance2 <- Prism$new(width = 10, height = 20, depth = 30) # この記法の方が推奨される content_instance3 <- Prism$new(width = 10, height = 20, depth = "hoge") # この場合でも型エラーがでる
## Error: invalid assignment for reference class field 'depth', should be ## from class "numeric" or a subclass (was class "character")
クラスメソッドの呼び出し
content_instance2$CalcContent() content_instance2$PrintResult()
## [1] 6000
参考 ここ