はじめに
2回目はクラスとかメソッドです。
環境
paiza.ioでこういう時は実行すると楽です
これを作った時のバージョンは以下です。バージョンはヘルプから確認できます。
Ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]
Java openjdk version "12" 2019-03-19
スコープの話
JavaもRubyもpublic,protected,privateが存在していますが、概念が違うので、項を分けました。
publicは同じで制限無しなのですが、protectedとprivateは違います。
詳しくはこちらを参考にさせていただきつつJavaエンジニア的な解釈で書いています。
なお、package privateの概念はRubyにはないようです。
クラススコープ
public(記述しない)とprivateが存在します。
インナークラスじゃないクラスをprivateにして使うみたいなシチュエーションはWebやってると使う機会がなさそうなので(今のところの感想)、見なかったことにします。
必要に応じてどういうスコープになるのか追加で学習します。
Javaでインナークラスも最近使ってないなーって感じなので、今回の記事ではスコープまでは扱いません。ご了承ください。
メソッドスコープ
public(記述しない)、protected、privateが存在してます。
publicは同じと捉えて良さそうなので、違う2つについて記述していきます。
private
違いが検証しやすかった方からのせます。
まずは下記のサンプルコードをご覧ください。
class A
private def print
p "a"
end
end
class B < A
def print2
print
end
end
b = B.new
b.print2
Javaと違ってクラス以外から使用してもRubyのprivateは動きます。
参考にさせていただいた記事を見るとprivate に設定されたメソッドは関数形式でしか呼び出せません
という記述になっているので、関数形式で呼び出せるサブクラスからも呼べてます。
きちんと動いていますが、Javaエンジニア的には少し気持ち悪いので注意が必要。
たぶん、他のケースでもアクセス出来ないと思ったら出来ちゃったがありそうです。
protected
色々調べたけど、良く分からないことが多いのと、生みの親であるMatzさんも今なら組み込まないと言われているというツイートを見かけたので見なかったことにします。
どうしても覚えなきゃいけないシーンに立ち会うまで初心者の方は見なかったことにしても良いかなと思います。
クラス
ここらへんは特に問題ありませんね。
使う側はクラス名.new
という形で生成して使用します。
public class A {
}
class A
end
ただし、Rubyは以下のような形でclassの拡張が行えるので、やろうと思えばなんでもありで出来ます。
class A
def print
p "a"
end
end
class A
def print2
p "b"
end
end
a = A.new
a.print
a.print2
生成したインスタンスに対しての拡張も行えるので、本当になんでもありな世界を作ることが出来ます。
こちらは生成したインスタンスに限定出来るので、使い道がないとは言えないかもしれません。
class A
def print
p "a"
end
end
a = A.new
# 特異クラスとして宣言する
class << a
def print2
p "b"
end
end
a.print
a.print2
継承
JavaもRubyも継承は単一継承です。
ただしJavaはinterfaceなら複数個いけるので、ちょっと無理矢理なことも出来なくはないです(特にJava8以降)。
Rubyは言語的に抽象クラスや抽象メソッド、interfaceをサポートしていないようなので、完全に継承といったら単一のクラスの継承となります。
mixinとかdelegation(ライブラリを使用する必要あり)がありますが、そちらについては全く別の概念となっているようで、継承とは別と考えた方が良さそうです。(本記事では扱いません、moduleもいったん対象外とします)
public class A extends B {
}
class A < B
end
メソッド
メソッドは引数無しと有りで分けます。
引数無し
Rubyは()
を省略することが可能となっています。
Rubyは特に戻り値の宣言が必要ないため、Docs書くなりしないと分かりづらいので注意が必要です。
Rubyの戻り値はreturnを記述するか、最後に評価された式の結果が返却されます。
Javaはreturnを明確に記述しないといけません。
public void method() {
System.out.println("a");
}
def method
print "a"
end
呼び出し時もRubyは省略可能となっています。
びっくりするから、無しの場合にどのような記述とするかはルールとして定めた方が良いと思います。
method()
method
引数有り
引数有りでもRubyは()
を省略可能となっています。
呼び出し側も同様です。
public void method(String a, String b) {
System.out.print(a);
System.out.print(b);
}
def method a, b
print a
print b
end
メソッドのネスト
Javaでは出来ませんが、Rubyはメソッド内にメソッドが宣言出来ます。
使用についてはネストして宣言した後から使用出来、前からは使用出来ません。
def method
print "a"
def methtod2
print "b"
end
methtod2
end
クラスメソッド
Rubyはクラスにメソッドを属することが出来ます。
Java的にはstaticメソッドと同様の使い方(考え方は違うと思います)が出来る感じです。
public class A {
public static void main() {
System.out.print("a");
}
}
class A
def self.method
print "a"
end
end
A::method
特異メソッドで宣言すればその中全てをクラスメソッドにすることも可能となっています。
複数のメソッドを定義する際に向いているとリファレンスには書いているため、分かりやすく分けてあげたほうが良いようです。
class A
def print
p "a"
end
end
class << A
def print2
p "b"
end
end
a = A.new
a.print
A::print2
単一でさらっとやりたい場合にはわざわざクラスから宣言せずともクラスメソッドを生成することも可能です。
def A.print2
p "b"
end
おわりに
とりあえずばーっと書き出しましたが、混沌の原因を作りやすくなっているのでしっかりとチームルールを作って運用すべきだなと感じました。
そしてまだ書けてないことがありますが、とりあえず初心者がスタートするには過不足なさそうな感じがしたので、ここで止めておきます。
Javaがかっちりしているので、Rubyの自由さは混乱しちゃいますね。