LoginSignup
19
14

More than 5 years have passed since last update.

C#とRubyの構文比較

Last updated at Posted at 2018-09-01

はじめに

普段の業務はC#なのですが、Rubyが楽しいと先輩に教わったのでプロを目指す人のためのRuby入門で基礎を学びました。
ソース書いててワクワクしたので、rubyを他の人にも触れてほしいと思い記しました。
余りに分量が大きくなるので、かいつまんで構文比較したいと思います。

分岐

単純分岐

csharp
int age = 20;
if (age == 20)
{
    // 処理1
}
else if (age > 20)
{
    // 処理2
}
else
{
    // 処理3
}
ruby
age = 20
if age == 20
  # 処理1
elsif age > 20
  # 処理2
else
  # 処理3
end

rubyは波括弧{}がないのでスマートですね。C#はVisualStudioのデフォルトのコード整形を使っていますが、波括弧で改行されるので縦幅をとられますね。

否定分岐

csharp
bool isSuccess = false;
if (!isSuccess)
{
    // エラー処理
}
ruby
is_success = false

if !is_success
  # エラー処理
end

# こうも書けます
unless is_success
  # エラー処理
end
  • C#の関数はパスカルケースで書くのですが、!と合わせると時々見づらいことがあります。例えば、IsSuccess()!IsSuccess()。こうした否定をunless(もし~でなければ)で表現できるのは明確でいいなぁと思います。

ワンライナーでの分岐

csharp
if (isSuccess) return true;
ruby
is_success = true
return true if is_success

# もちろん、こうも書けます
if is_success then return true end
  • rubyは先に結果を書けるので、まず何を読み手に伝えたいかで使い分けられますね。

繰り返し

each

csharp
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}");
}
ruby
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

csharp
var numbers = new List<int>() { 1, 2, 3 };
var new_numbers = numbers.Select(n => n * 10);
Console.WriteLine(new_numbers);    // [10, 20, 30]
ruby
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以外にも超便利なメソッドが用意されているので、マスターしたら複雑な処理がすごく簡潔に書けるはずです。

ハッシュ

基本

csharp
// 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)};
ruby
person = {'name' => 'A', 'age' => '18', 'birthday' => '2000-01-02'}
  • シンボルに続く・・・↓

シンボル

  • C#にはないRuby特有のもの
  • コード上は文字列だが、内部では整数として扱うため高速
  • 同値の文字列なら同じシンボルが使われる(省メモリ)
  • ハッシュキーでよく使われる
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'}

クラス

生成、プロパティ

csharp
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));
ruby
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というものです。
csharp
// 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 "ワン!";
    }
}
ruby
# 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触ってくれる人が増えたらいいなと思います!

19
14
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
14