[译林系列--Ruby] 通过IronRuby和C#学习Ruby[2]

声明:文章版权归原作者所有,转贴请标明原出处及本文地址,原文地址:http://www.codethinked.com/post/2008/07/21/Learning-Ruby-via-IronRuby-and-C-Part-2.aspx

上一次我们讨论了与变量有关的话题,涉及了全局变量,本地变量,以及实例变量和静态变量。在这次的文章中,我们将继续深入讨论ruby的类以及开始定义方法和解决参数传递。

但在开始前,我还是要先简单介绍一下输出命令,这可以使你在之后的学习中更为顺畅。在C#中输出语句为:

Console.WriteLine("My test value");

但在Ruby中:

puts "My test value"

很简单哈~现在你可以在终端输出你要的结果了,那么下面开始我们今天的学习

首先,让我们先以C#为例创建一个带构造器和方法的类:

public class Person

{

public string FirstName { get; set; }

public string LastName { get; set; }

public Person(string firstName, string lastName)

{

this.FirstName = firstName;

this.LastName = lastName;

}

public string FirstAndLastName()

{

return String.Format("{0} {1}", FirstName, LastName);

}

}

这里你应该注意到Person类有两个属性并且它们将在构造器里完成初始化。而后我们构造了一个方法,其将使用String.Format来返回first name 和 last name。那么Ruby呢?下面你可能就会对Ruby的简单而感到惊讶了~

class Person

attr_accessor :first_name

attr_accessor :last_name

def initialize(first_name, last_name)

self.first_name = first_name

self.last_name = last_name

end

def first_and_last_name

"#{@first_name} #{@last_name}"

end

end

事实上,在Ruby中我们用arrtibute accessors来代替C# 中的properties.而后又特别创建了一个特殊的函数“initialize",它相当与一个构造器。在Ruby中我们调用此函数来初始化一个新的类实例,虽然在之后我们会介绍到你实际上并没有必要显示的调用它。接下来,我们介绍一下"first_and_last_name”函数,它将返回一个由first name和last name连接的串。注意,这里我们并没有定义它的返回类型,这是因为Ruby中所有变量都返回一个值而已,不论它是NULL或者是一个有效值。再者你会发现我们根本没有写返回语句,这是因为Ruby中将每一个语句都视作一个返回语句。最后一点,我们在string中直接使用了变量,这是Ruby的语法糖提供的便捷。

在C#中使用这个类会用到new运算符,例如:

var person = new Person("Ted", "Smith");

而在Ruby中却是new函数:

person = Person.new("Ted", "Smith")

另一个C# 中有用的关键字是“params”,他用来向函数传递变量:

public string Concat(params string[] items)

{

string result = "";

foreach (string item in items)

{

result += item;

}

return result;

}

在Ruby中我们用“*”来完成同样的功能

def concat(*items)

result = ""

items.each do |item|

result += item

end

result

end

实质上,Ruby的函数完成了同样的功能,并且其更易读。在C# 版本的示例中,我们用到了foreach语句来循环处理数组。而在Ruby中,我们利用each函数来处理每一个元素。Each函数可能看上去并不像一个函数,(译者著:你可以看到each函数并没有用到圆括号),但实质上,这是因为圆括号在Ruby中一般是可选的。

因此,如果圆括号可以省略,我们可以修改我们之前创建person类的例子如下:

person = Person.new "Ted", "Smith"

这样写,一点问题都没有,你完全可以这样做。但我为什么说这是“一般可选”的呢?这是因为,在有的情况下,例如你内嵌某个函数在语句中,如果省略了圆括号会导致二义性。比如:

person.concat(person.first_and_last_name, "test")

这时如果我们去掉括号:

person.concat person.first_and_last_name "test"

事实上,此时Ruby会试图将test作为person.first_and_last_name的参数,而实质上它是没有函数的,这就造成了一个错误的发生。因此,圆括号只是可选得,那么逗号呢,它是否也是可选的?让我们看个例子

person = Person.new "Ted" "Smith"

哈,如果我们试图这么做就会受到一个错误报告,它指明我们没有能够给person.new提供所需足够参数。那么它认为我们提供了几个参数呢?答案是一个,即“Ted"。那么参数传递是按数组形式传的吗?不是。事实上在Ruby中,"+"符号在字符串中是可选的,这就意味着,连接字符串可以有很多种方案,但我仍坚持使用+运算符。

正如我们先前提到的each函数,它的参数是什么呢?实际上,在"do"和"end"之间的内容就是它的参数。在Ruby中,这被称为一个block。作为C# 程序员,这个例子或许能让你更深刻体会:

items.each { |item| result += item }

把这作为一个action delegate,并使拓展的函数定义看上去像这样:

public void Each<T>(this IEnumerable<T> list, Action<T> func)

{

foreach (T item in list)

{

func(item);

}

}

现在我们可以在我们的C# 代码中调用它了

items.Each(delegate(string item) { result += item; });

当然我们也可以使用Aggregate function (also called Fold) 并且 Lambda syntax 能使它看起来更相似些。但我不想让你对block和lambda产生过多的困惑 ,因为他们根本不是一回事。不过不必担心,Ruby也有 lambdas!

好了,今晚就说到这。在下一节里,我们将会讨论控制结构并且再深入讨论block,他们都是十分重要的概念!

我希望这篇文章对你的学习有所帮助~