最近更新: 2009-12-07

以Ruby觀點來看 C++ template

從 C++ Template 到 Java Generic,一步一步來一文,我用 Java 的泛型語法改寫了一個 C++ 樣板類別。 我也用 PHP、JavaScript 和 Ruby 來做同樣的事,看看這些動態語言有沒有泛型處理能力。

我要用 Ruby 改寫的 C++ 樣板類別,其源碼同從 C++ Template 到 Java Generic,一步一步來。本文不再重複,直接說明 Ruby 的改寫過程。

Ruby 改寫過程

Ruby 語法與 C++ 語法的差異性較大。不細述改寫內容。

Ruby 中,變數名稱以 @ 開頭者,則為實體變數,且所有實體變數的存取屬性都是 private。Ruby不允許 public 的資料成員,只能透過方法存取。

Cx 有兩個建構子,一個是無參數的預設建構子,另一個是一個參數的建構子。Ruby 可以用參數預設值的方式簡化建構子的改寫動作,寫成一個。

class Cx
  @data

  public
  #ruby 的建構子名稱為 initialize, 支持參數預設值

  def initialize(v = 0)
    @data = v
  end

  def getData()
    return @data.value()
  end
end

class N
  @n

  public
  def initialize(v = 0)
    @n = v
  end

  def value
    return -@n;
  end
end

class M
  @m

  public
  def initialize(v = 0)
    @m = v
  end

  def value
    return @m * 10;
  end
end

class S
  @s

  public
  def initialize(v = "")
    @s = v
  end

  def value
    return @s;
  end
end

緊接著上面的內容,接著的要改寫 C++ 的 main() 。在 Ruby 中不需要指示程序進入點,直接寫即可。


//不需要特殊的樣板語法
n = N.new(1)
cn = Cx.new( n );
puts cn.getData()

m = M.new(1)
cm = Cx.new( m );
puts cm.getData

s = S.new "hello"
cs = Cx.new s
puts cs.getData

#調用與定義方法時,ruby 可以省略包圍參數的括號( ) 。

在 C++ 中的樣板類別 Cx ,到了 Ruby 中之後,跟一般的類別沒兩樣。 因為動態語言的語義,基本上就是泛型的。

有些沒接觸過動態語言的人,對於泛型有一種奇怪的誤解,他們認為動態語言並沒有泛型語法,所以動態語言沒有泛型能力。我在C++和動態語言的泛型一文中曾經駁斥過這一論點。從語意看,動態語言其實就是泛型的。

移除 C++ 型別資訊,以 Ruby 語法改寫的 N, M, S 類別定義,也僅僅只剩兩行程式碼不同,這意味著我們可以進一步重構彙整。

前面提到在 Ruby 不允許 public 資料成員,所有資料成員都只能透過方法存取。而在本文的改寫過程中並沒有提到 Ruby 其實有簡便的屬性定義語法(Class Attribute Declarations)。如下列所示範。

class AttrDemo
  attr_reader :x    #read-only

  attr_accessor :y  #read/write


  def initialize
    @x = 1
  end
end

demo = AttrDemo.new

begin
  demo.x = 2
rescue
  puts 'attriute "x" is read only'
end

demo.y = 2

puts demo.x
puts demo.y

C# 也有類似的語法,稱為自動實作屬性(Automatically implemented property),例如:

public int X { get; private set; }
public int Y { get; set; }

其實方法 attr_read, attr_accessor 都採用預設的方式存取資料成員。其預設方式如下:

class AttrDemo {
  private:
    int x;
    int y;
    
  public:
    int getX() {
        return this.x;
    }
    
    int getY() {
        return this.y;
    }
    int setY(int v) {
        this.y = v;
    }
}

方法 attr_read, attr_accessor 自動幫程序員完成取值與存值的程式碼。

class AttrDemo
  #attr_reader :x    #read-only

  def x
    @x
  end

  #attr_accessor :y  #read/write

  def y
    @y
  end
  def y=(val)
    @y = val
  end
end
相關文章
樂多舊網址: http://blog.roodo.com/rocksaying/archives/10934767.html