その他
    ホーム 技術発信 DoRuby rubyistのためのscala (3) クラスとオブジェクト指向

    rubyistのためのscala (3) クラスとオブジェクト指向

    この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。


    Rubyで書くあれはScalaだとどう書くの?シリーズ。 今回はクラスとオブジェクト指向について。

    クラス

    クラスの宣言と継承

    Ruby

    class Foo < Bar
    end

    Scala

    class Foo extends Bar {
    }

    コンストラクタ

    Rubyではinitializeという名前のメソッドを定義する。

    class Foo
      def def initialize(bar)
        # new した時点でここが実行される
      end
    end

    Scalaにはコンストラクタを複数定義できるが、ここではデフォルトのコンストラクタについて説明する。

    デフォルトのコンストラクタはクラス定義のブラケット内にそのまま記述できる。
    引数はクラス名の後ろのカッコ内に書く。

    class Foo(bar: Int) {
      // new した時点でここが実行される
    }

    モジュール

    Ruby

    module Foo
      def bar
      end
    end

    Scala

    trait Foo {
      def bar: Unit = {
      }
    }

    barというメソッドを持つtrait Fooを定義することができる。

    Mixin

    Scalaではtraitを継承することでmixinを行う。

    Ruby

    module Bar
    end
    
    class Foo
      include Bar
    end

    Scala

    trait Bar {
    }
    
    class Foo extends Bar {
    }

    ひとつのクラスが複数のtraitをmixinする場合、二つ目以降は with というキーワードを使う。

    Scala

    class Foo extends Bar with Baz with Hoge {
    }

    TODO: prependusingについても調べて書く

    名前空間

    Rubyではモジュールを名前空間として使うことができる。

    Ruby

    module Foo
      module Bar
        class Baz
        end
      end
    end
    
    baz = Foo::Bar::Baz.new

    Scalaではパッケージのほか、シングルトンオブジェクトも名前空間として使うことができる。

    Scala

    package foo
    object Bar {
      class Baz {
      }
    }
    
    val baz = new foo.Bar.Baz()

    TODO: import について書く

    メソッド

    キーワードは同じ def
    引数と返り値の型を指定する。

    Ruby

    class Foo
      def bar(a, b)
        a + b
      end
    end

    Scala

    class Foo {
      def bar(a: Int, b: Int): Int = {
        a + b
      }
    }

    プロパティとアクセサ

    デフォルトのゲッター、セッター

    Ruby

    class Foo
      attr_accessor :bar, :baz
      def initialize(bar, baz)
        @bar = bar
        @baz = baz
      end
    end
    
    foo = Foo.new(1, "abc")
    foo.bar  # => 1
    foo.baz  # => "abc"

    Scala

    class Foo(var bar: Int, var baz: String) {
    }
    
    val foo = new Foo(1, "abc")
    foo.bar  // => 1
    foo.baz  // => "abc"

    セッターの実装

    Ruby

    class Foo
      attr_reader :bar
      def bar=(i)
        @bar = i
      end
    end
    
    foo = Foo.new
    foo.bar = 1
    foo.bar  # => 1

    Scala

    class Foo {
      private var _bar: Int = _
      def bar = _bar
      def bar_=(i: Int): Unit = this._bar = i
    }
    
    val foo = new Foo()
    foo.bar = 1
    foo.bar  // => 1

    Scalaのセッターメソッドは def 変数名_=(引数): Unit = ??? という形で定義する。

    演算子メソッド

    Rubyでメソッドとして再定義可能な演算子

    |  ^  &  <=>  ==  ===  =~  >   >=  <   <=   <<  >>
     +  -  *  /    %   **   ~   +@  -@  []  []=  ` ! != !~

    Scalaで再定義できない予約語、キーワード
    FAQ How do I find what some symbol means or does?より引用)
    (これ以外の記号、英数字は使えるらしい)

    // Keywords
    <-  // Used on for-comprehensions, to separate pattern from generator
    =>  // Used for function types, function literals and import renaming
    // Reserved
    ( )        // Delimit expressions and parameters
    [ ]        // Delimit type parameters
    { }        // Delimit blocks
    .          // Method call and path separator
    // /* */   // Comments
    #          // Used in type notations
    :          // Type ascription or context bounds
    <: >: <%   // Upper, lower and view bounds
    " """      // Strings
    '          // Indicate symbols and characters
    @          // Annotations and variable binding on pattern matching
    `          // Denote constant or enable arbitrary identifiers
    ,          // Parameter separator
    ;          // Statement separator
    _*         // vararg expansion
    _          // Many different meanings

    どちらも記号を名前としたメソッドを定義することで演算子を定義できる。

    class Foo
      def +(other)
        "add method"
      end
    end
    
    foo1 = Foo.new
    foo2 = Foo.new
    foo1 + foo2  # "add method"
    class Foo {
      def +(other: Foo): String = "add method"
    }
    
    val foo1 = new Foo
    val foo2 = new Foo
    foo1 + foo2  // "add method"

    引数のデフォルト値

    Ruby

    class Foo
      def bar(baz = 1)
        baz
      end
    end
    
    foo = Foo.new
    foo.bar()  # => 1
    foo.bar(2)  # => 2

    Scala

    class Foo {
      def bar(baz: Int = 1): Int = {
        baz
      }
    }
    
    val foo = new Foo()
    foo.bar()  // => 1
    foo.bar(2)  // => 2

    可変長引数

    Rubyでは定義するときも呼び出すときも * という記号をまえにつける。

    class Foo
      def bar(baz, *hoge)
        # 2つめ以降の引数はhogeに配列として入る
      end
    end
    
    foo = Foo.new
    baz = 1
    hoge = ["foo", "bar"]
    foo.bar(baz, *hoge)

    Scalaでは定義するときは *をうしろにつけ、呼び出すときは :_* という記号をうしろにつける。

    class Foo {
      def bar(baz: Int, bar: String*): Unit = {
        // 2つめ以降の引数は bar にSeqとして入る
      }
    }
    
    val foo = new Foo
    val baz = 1
    val hoge = Seq("foo", "bar")
    foo.bar(baz, hoge:_*)

    ※読みやすいレイアウトでまとめましたサイトを作りましたので、こちらもご参照ください。
    http://kkismd.github.io/rb2scala/