はじめに
普段の業務はC#なのですが、Rubyが楽しいと先輩に教わったのでプロを目指す人のためのRuby入門で基礎を学びました。
ソース書いててワクワクしたので、rubyを他の人にも触れてほしいと思い記しました。
余りに分量が大きくなるので、かいつまんで構文比較したいと思います。
分岐
単純分岐
int age = 20;
if (age == 20)
{
// 処理1
}
else if (age > 20)
{
// 処理2
}
else
{
// 処理3
}
age = 20
if age == 20
# 処理1
elsif age > 20
# 処理2
else
# 処理3
end
rubyは波括弧{}がないのでスマートですね。C#はVisualStudioのデフォルトのコード整形を使っていますが、波括弧で改行されるので縦幅をとられますね。
否定分岐
bool isSuccess = false;
if (!isSuccess)
{
// エラー処理
}
is_success = false
if !is_success
# エラー処理
end
# こうも書けます
unless is_success
# エラー処理
end
- C#の関数はパスカルケースで書くのですが、!と合わせると時々見づらいことがあります。例えば、
IsSuccess()
と!IsSuccess()
。こうした否定をunless
(もし~でなければ)で表現できるのは明確でいいなぁと思います。
ワンライナーでの分岐
if (isSuccess) return true;
is_success = true
return true if is_success
# もちろん、こうも書けます
if is_success then return true end
- rubyは先に結果を書けるので、まず何を読み手に伝えたいかで使い分けられますね。
繰り返し
each
var list = new List<string>() { "A", "B", "C" };
for (var i = 0; i < list.Count; i++)
{
Console.WriteLine($"{i}:{list[i]}");
}
// 私が書いた最初の恥ずかしいやり方(無理にrubyのeachを意識してしまっていました。。)
var index = 0;
var list = new List<string>() { "A", "B", "C" };
foreach (var value in list)
{
Console.WriteLine($"{index}:{list[index]}");
index += 1;
}
// munielさんに教えてもらったrubyの記述に似た書き方
foreach (var (v, i) in list.Select((v, i) => (v, i))) {
Console.WriteLine($"{i}:{v}");
}
list = ["A", "B", "C"]
list.each.with_index do |v, i|
puts "#{i}:#{v}"
end
# ワンライナーで改行なしでも書けるのですが、見づらいので、、、
list.each.with_index do |v, i| puts "#{i}:#{v}" end
# ワンライナーだと{}ブロックでの書き方が多いらしいです。
list.each.with_index { |v, i| puts "#{i}:#{v}" }
-
C#だとforeachの中で添え字(index)も使う必要がある場合、添え字用の変数を用意するのが面倒だと思う時があります。(←for使う記述に訂正 2018/09/02)rubyならeachの後にwith_indexをメソッドチェーンで呼ぶだけで添え字が取得できるのは楽ですね。 - (2018/09/02追記)C#のLinqでも第二要素でindexを取得できるの知りませんでした!
map
var numbers = new List<int>() { 1, 2, 3 };
var new_numbers = numbers.Select(n => n * 10);
Console.WriteLine(new_numbers); // [10, 20, 30]
numbers = [1, 2, 3]
new_numbers = numbers.map { |n| n * 10 }
p new_numbers # [10, 20, 30]
- rubyでmapを知ったときはおぉ!かっこいい!と思いましたが、C#のLinqでも同様のことが簡潔にかけますね。
- ただし、rubyのArrayやEnumerableのメソッドはmap以外にも超便利なメソッドが用意されているので、マスターしたら複雑な処理がすごく簡潔に書けるはずです。
ハッシュ
基本
// C#だとDictionaryに該当します
var person = new Dictionary<string, object>();
person["name"] = "tanaka";
person["age"] = 18;
person["birthday"] = new DateTime(2000, 1, 2);
// lensoukoさんに教えてもらったやり方。匿名クラスの方が確かにrubyのハッシュに近いですね!
var person = new {name = "tanaka", age = 18, birthday = new DateTime(2000, 1, 2)};
person = {'name' => 'A', 'age' => '18', 'birthday' => '2000-01-02'}
- シンボルに続く・・・↓
シンボル
- C#にはないRuby特有のもの
- コード上は文字列だが、内部では整数として扱うため高速
- 同値の文字列なら同じシンボルが使われる(省メモリ)
- ハッシュキーでよく使われる
# つまり、このようにキーを文字列で書くよりも
person = {'name' => 'A', 'age' => '18', 'birthday' => '2000-01-02'}
# シンボルを使って書いた方がよい
person = {:name => 'A', :age => '18', :birthday => '2000-01-02'}
# シンボルはこうも書ける(:の位置が後ろで=>が不要)
person = {name: 'A', age: '18', birthday: '2000-01-02'}
クラス
生成、プロパティ
public class Member
{
public string Name { get; set; }
public int Age { private get; set; }
public DateTime Birthday { get; }
public Member(string name, int age, DateTime birthday)
{
Name = name;
Age = age;
Birthday = birthday;
}
}
// クラス生成
var member = new Member("田中", 18, new DateTime(2000, 1, 2));
class Member
attr_accessor :name
attr_writer :age
attr_reader :birthday
def initialize(name, age, birthday)
@name = name
@age = age
@birthday = birthday
end
end
# クラス生成
member = Member.new("田中", 18, Time.new(2000, 1, 2))
- プロパティはattr_~ {シンボル} を使って定義します。
- initializeメソッドはnewしたタイミングで呼び出されます。
- rubyではreturnを明記しなくても最後の実行結果が戻り値になります。
継承、オーバーライド、抽象メソッド
- rubyに抽象クラスやインターフェースの概念はありません。あるのはダックタイピングです。ざっくり言えば、同じメソッドが実装してあり、呼び出せればOKというものです。
// SuperClass
public abstract class Animal {
public string Name { get; }
public Animal(string name) {
Name = name;
}
public virtual void Walk() {
Console.WriteLine("歩きます。");
}
public abstract string Say();
}
// SubClass
public class Dog : Animal {
public int Age { get; } // SubClass固有のプロパティ
public Dog(string name, int age) : base(name) {
Age = age;
}
public override void Walk() {
base.Walk(); // ←SuperClassメソッドの呼び出し
Console.WriteLine("トコトコと。");
}
public override string Say() {
return "ワン!";
}
}
# SuperClass
class Animal
attr_reader :name
def initialize(name)
@name = name
end
def walk
puts '歩きます。'
end
# 書かなくてもいいけど開発者向け
def say
# C#でいうところの throw new NotImplementedException();
raise 'サブクラスで実装してください。'
end
end
# SubClass
class Dog < Animal
attr_reader :age
def initialize(name, age)
super(name) # superはSuperClassのメソッド呼び出し
@age = age
end
def walk
super # superはSuperClassのメソッド呼び出し
puts 'トコトコと。'
end
def say
puts 'ワン!'
end
end
まとめ
プロを目指す人のためのRuby入門を読んで数本簡単なアプリを作成してみました。
もちろん、自分にとって習いたての言語というのもあり、Rubyで書くのはワクワク感じました。
ただ、それ以外にも、やりたい処理が数行のコードで実現できるという率直な感動。しかも数キロバイトの軽いファイル1つで。C#で同じことしようとしたら、コンソールプロジェクト作成してnugetして、ビルドしてと。。。。rubyの方が開発速度、断然早いです。
それ以外に、私が感動したのが、単体テストのスピード感でした。C#はコンパイラ言語なのでVisual Studioで毎回ビルドが走り単体テストを実行するたびに数十秒待たされるのです。(スクリプト言語をやっている方からすると信じられないくらい遅いですよね。。)
一方、Rubyはスクリプト言語なのでリズミカルに開発を進めることが出来ました。このおかげで、Rubyでは思考を途絶えさせずに開発できるのがメリットだと気づきました。そして、これが自分にとっては重要な要素でした。
たぶん、もっとダックタイピングを使った設計を考えていくと、さらにRubyの魅力に気付けるのだと思いました。
拙い記事でしたが、少しもRuby触ってくれる人が増えたらいいなと思います!