Rubyの本、買ってきた。「たのしいRuby」勉強しながらtwitterに投稿した文を加筆訂正してQiitaに投稿する。今回は、いよいよラスボス、クラス。
Twitter、Green_helmet@bethlehem4099
Qiita、@dosaidon
参考文献
この記事は以下の情報を参考にして執筆しました。
-たのしいRuby、高橋征義、後藤裕蔵著、 まつもとゆきひろ監修、SBクリエイティブ株式会社、第6版2019年
-『たのしいRuby 第6版』サポートページ、ソースコード
クラス
用語の定義:
まずクラスから(意訳)
✅クラスはオブジェクトの種類を表すもの
✅クラスはRubyでは型
✅何らかのクラスに全てのRubyのオブジェクトは属している
例1:Arrayクラスのオブジェクトが配列、例a=[1,2,3]
例2:Stringクラスのオブジェクトが文字列、例s= "Ruby"
✅クラスのオブジェクトをインスタンスと言う
例1:配列はArrayクラスのインスタンス
例2:文字列はStringクラスのインスタンス
はい
✅クラスは雛形あるいは設計図
✅インスタンスは雛形あるいは設計図をもとに作ったもの
たい焼きの型とたい焼きの絵
宇宙猫…
クラスの説明がよくわからない
かなり意訳した
ああ、
たい焼きは粒餡かな、それともこし餡か
東京三大たい焼きは人形町柳屋、麻布十番浪速屋総本店、四谷たいやきわかば
白いたい焼きもあったな
乱獲がたたって今や絶滅危惧種
はっ、Rubyと関係無い
Green_helmet@bethlehem4099·7月24日
クラスを作る
# receipt.rb参照しコメントを独自に追加
class Receipt # クラス宣言開始
def initialize(name) # initializeメソッド、コンストラクタ
@name=name #@name:インスタンス変数の定義
@lines=[] #@lines:インスタンス変数の定義、空
end
def lines=(line) #lines=:「英字=」の変数名が許される!
@lines=line #@lines:インスタンス変数のセッター
end
def calc # 計算メソッド、価格と数量の積和を求める
total=0
@lines.each do | line |
total += line[:price] * line[:num]
end
total
end
def output # 出力メソッド
puts "レシート #{@name}"
@lines.each do | line |
puts "#{line[:name]} #{line[:price]} x #{line[:num]}"
end
puts "合計金額: #{calc}円"
end
end#クラス宣言終わり
r = Receipt.new("ストアA") # レシートクラスのインスタンス/オブジェクトを作る
r.lines= [{ name:"卵", price:139, num:1 },
{ name:"きゅうり", price:42, num:3 }] # レシートの名称と金額、数量をセット
r.output#出力メソッド
➜ ruby receipt.rb
レシート ストアA
卵 139 x 1
きゅうり 42 x 3
合計金額: 265円
この例題は複雑だがコメントのように理解するとわかる。うん、Rubyのクラス定義を完全に理解した
Green_helmet@bethlehem4099·7月24日
もっと単純なクラスを自分で作って見る
# mini_class.rb
class MiniClass
def initialize(var)
@x = var
end
def meth1
puts @x
end
def meth2
puts @x * 2
end
end
obj=MiniClass.new(2020)
obj.meth1
obj.meth2
➜ ruby mini_class.rb
2020
4040
Rubyのクラスのキモ
ごく雑に要約すると上の例のように関数(メソッド)をclass クラス名
とend
で囲ったものがクラスで、使うときはオブジェクト名=クラス名.new
と書くと新しくオブジェクトが作られる(new)、さらにオブジェクト名.関数名(メソッド名)
と書くとクラス内のメソッドが実行される。他に色々マイナーチェンジがあるがクラスのキモはこれ。
RubyとPythonの比較
Rubyは意外なことにPythonよりタイプ量が少ない
まず (self): が無いのと、self. が@に入れ替わる、あと()も無い。
Pythonでクラスを書いているとやたらとself.がでてくる。
自己中なヘビ。
Green_helmet@bethlehem4099·7月25日
つぎ、アクセッサ
class MyClass
attr_accessor:name
def initialize(name);@name=name end
def meth; puts @name; end
end
obj=MyClass.new("初期")
puts obj.name
obj.meth
obj.name="変更"
obj.meth
puts obj.name
初期
初期
変更
変更
アクセッサ:インスタンス変数(@が付いてる変数)を楽に読み書き出来るようにする。
あと、Rubyはプログラムを改行せずにコンパクトに書くこともでき自由度が高い
つぎ、特別な変数self
エッ、Rubyにもself.があるの?
@はself.の代わりじゃないのか
@がつくのは変数だけか
Green_helmet@bethlehem4099·7月29日
つぎ、クラスメソッド
class << HelloWorld
def hello(name)
puts "#{name} said hello."
end
end
HelloWorld.hello("John")
楽しいRuby、クラスメソッドの例題が動かない。
親クラスHelloWorldが抜けているとのアドバイスを頂いたので追加。
Green_helmet@bethlehem4099·7月29日
class HelloWorld
end
class << HelloWorld
def hello(name)
puts "#{name} said hello."
end
end
HelloWorld.hello("John")
~ % ruby hello_world_inheritance.rb
John said hello.
動いた、ありがとうございます。
Green_helmet@bethlehem4099·7月30日
class HelloWorld6
class << self
def hello(name)
puts "#{name} said hello."
end
end
end
HelloWorld6.hello("John")
➜ ruby class_method6.rb
John said hello.
ああ、これは動く
Rubyクラスメソッドのサンプル
Green_helmet@bethlehem4099·7月30日
class HelloWorld7
def self.hello(name)
puts "#{name} said hello."
end
end
HelloWorld7.hello("Tommy")
➜ ruby class_method7.rb
Tommy said hello.
これも大丈夫
Rubyクラスメソッドのサンプル
Green_helmet@bethlehem4099·7月30日
class HelloWorld8
def HelloWorld8.hello(name)
puts "#{name} said hello."
end
end
HelloWorld8.hello("Roger")
➜ ruby class_method8.rb
Roger said hello.
これも動く
Rubyのクラスメソッドのサンプル
Green_helmet@bethlehem4099·7月30日
class HelloWorld9
def self.hello(name)
puts "#{name} said hello."
end
end
HelloWorld9.hello("Mark")
➜ ruby class_method9.rb
Mark said hello.
ちゃんと動く
Rubyのクラスメソッドのサンプル
Green_helmet@bethlehem4099·7月30日
見た目の感じはself.関数名の書き方が好きかな。
Pythonでは@staticmethodに相当すると思うけどRubyの方がスマート。
クラスメソッドはこれでおしまい。
Rubyの勉強からは少し外れるが、変数の型宣言のある言語の方がないRubyのような言語より良いというTwitterがたくさん流れてくる。
でも、変数の型宣言のある言語にはとても小さな欠点があって、それはプログラムを期限内に開発できない事なんだよね。
Green_helmet@bethlehem4099·7月31日
つぎ、クラスの中の定数
class Constant
Version = 1.0
def self.hello
puts "Version is #{Version}"
end
end
Constant.hello
print "Version is ", Constant::Version, "\n"
➜ ruby const.rb
Version is 1.0
Version is 1.0
クラスの中の定数
はい
Green_helmet@bethlehem4099·7月31日
つぎ、クラス変数
例題が複雑すぎて理解できないので独自に作成
class ClVar
@@cnt=0
def initialize
@cnt=0
end
def cnter
@@cnt+=1
@cnt+=1
puts "@@cnt=#{@@cnt}"
puts "@cnt=#{@cnt}","\n"
end
end
r1=ClVar.new
r2=ClVar.new
r1.cnter
r2.cnter
r2.cnter
r1.cnter
➜ ruby cvar.rb
@@cnt=1
@cnt=1
@@cnt=2
@cnt=1
@@cnt=3
@cnt=2
@@cnt=4
@cnt=2
@@変数はインスタンスをまたいで値を変更・参照できる
@変数はそれぞれのインスタンスで独立に値を変更・参照できる
よくできている
Green_helmet@bethlehem4099·8月12日
つぎ、メソッドの呼び出しを制御する
class AccessTest
def pub
puts "pub is a public method."
end
public:pub
def priv
puts "priv is a private method."
end
private :priv
end
access = AccessTest.new
access.pub
access.priv
➜ ruby Access_test.rb
pub is a public method.
Access_test.rb:18:in `<`: private method `priv` called for #<AccessTest:0x000000014b938450> (NoMethodError)
プライベートなメソッドは自分のインスタンスでも呼べない
ふむ
Green_helmet@bethlehem4099·8月12日
ちなみに半角スペースが意味を持つ
public:pub #OK
public :pub #OK
public: pub #ERROR
public : pub #ERROR
Green_helmet@bethlehem4099·8月12日
つぎ
class AccessTest
public
def pub
puts "pub is a public method."
end
private
def priv
puts "priv is a private method."
end
end
access = AccessTest.new
access.pub
access.priv
Green_helmet@bethlehem4099·8月12日
➜ ruby Access_test2.rb
pub is a public method.
Access_test2.rb:14:in `<main>`: private method `priv` called for #<AccessTest:0x000000014b883a50> (NoMethodError)
コッチの書き方の方が馴染み深いが
C++はprivate:だったような…
Green_helmet@bethlehem4099·8月13日
def swap(other)
tmp_x, tmp_y = @x, @y
@x,@y= other.x, other.y
other.x, other.y=tmp_x, tmp_y
return self
end
end
p0 = Point.new
p1 = Point.new(1.0, 2.0)
p [p0.x, p0.y]
p [p1.x, p1.y]
p0.swap(p1)
p [p0.x, p0.y]
p [p1.x, p1.y]
p.x=10.0
➜ ruby point.rb
[0.0, 0.0]
[1.0, 2.0]
[1.0, 2.0]
[0.0, 0.0]
point.rb:23:in `<main>`: undefined method `x=` for nil:NilClass (NoMethodError)
Green_helmet@bethlehem4099·8月13日
よく分からんが次
RubyのProtectedはC++と大体同じで、PythonにはProtectedが無いと言うことかな。
あと、Rubyには友達(Friend)がいないと。
まあ、今日はこれぐらいにしといたるわ。
Green_helmet@bethlehem4099·8月14日
いよいよ大物、クラスの継承
class String
def count_word
ary = self.split(" ")
return ary.size
end
end
str = "An example of inheritance in Ruby."
p str.count_word
➜ ruby ext_string.rb
6
Green_helmet@bethlehem4099·8月14日
組み込みクラスのStringを継承して自前のcount_wordメソッドを追加する
ふむ、なかなかキレイ
Green_helmet@bethlehem4099·8月14日
つぎ、オーバーライド
class RingArray < Array
def [](i)
inx=i % size
super(inx)
end
end
wday=RingArray["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]
print wday[-1],","
print wday[0],","
print wday[1],","
print wday[2],","
print wday[3],","
print wday[4],","
print wday[5],","
print wday[6],","
puts wday[7]
→ ruby ring_array.rb
Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday,Monday
Arrayクラスの[]メソッドをオーバーライドしたということか
了解しました
Green_helmet@bethlehem4099·8月17日
つぎ、ベーシックオブジェクト
puts Object.instance_methods,"\n\n"
puts BasicObject.instance_methods
〜略〜
!
==
!=
__id__
equal?
instance_eval
instance_exec
__send__
あまりにBasicすぎてpすら無かった
終わり
つぎ、Alias
Green_helmet@bethlehem4099·8月17日
class C1
def hello
"hello"
end
end
class C2<C1
alias old_hello hello # old←new
def hello
"#{old_hello}, again"
end
end
obj1 = C1.new
p obj1.hello
obj2 = C2.new
p obj2.old_hello
p obj2.hello
➜ ruby alias_sample.rb
"hello"
"hello"
"hello, again"
クラスのメソッド名を後から書き換える、う〜ん
大混乱の種まきのような気がするが、まあいっか
Green_helmet@bethlehem4099·8月17日
つぎ、undef
undef method_name
undef: method_name
はい
これでクラスは終わり。どっとはらい。
Green_helmet@bethlehem4099·8月17日