DennisRitchie 发表于 2007-08-22 23:04

刚刚仔细看了一遍,忍不住再再赞一遍楼主的讲解水平,希望楼主以后多发贴,这里我也有几个问题:

引用1
然后是可能会让 PHPer 奇怪的冒号。
....
@log 和 @cpu_time 是这个类的实例变量(instance variable),前面加一个 @ 以辩别。加 @@ 则是类变量(class variable)

首先我没有完全理解你所讲的Symbol类,不知道Zend Engine的做法这么做是否和c++ stl中string的copy on write有类似的地方?

其次,在ruby语言中,变量有些情况下要加上:@等前缀(就像perl变量的$@%前缀),这么做虽然提高了效率,但是对于学习者来说却增加了负担,相对而言,python、php就比较"consistency"。

引用2
首先,建立了一个 Hash。我暂时还不知道 columns 是不是必须先赋值 Hash.new,才能用 [],不过保险起见,先这样搞。
我没有用过ruby,正在学习perl和python,按照我的猜测,应该是必须的。在Python中:
[*]变量不用申明
[*]简单变量可以直接使用
[*]复合变量(数组、链表、字典、用户自定义的类)必须先显示的创建,才可以使用他们


引用4

columns[:host] = /^http:\/\/([^\/]+)/.match(data)

我觉的把这行代码颠倒过来更容易理解,因为data是被操作的对象:

columns[:host] = data.match(/^http:\/\/([^\/]+)/)


Ruby 也有 =~ 操作符,但是由于本人对 Perl 实在不熟,所以没觉得好用,就用 match 吧。
刚学perl的时候,我也觉的 =~ 怪怪的,前几天想通了,如果用户熟悉vi的话,那么perl的正则表达式就很容易理解,在perl中正则表达式的形式:

[*] $text =~ /patten/
[*] $text =~ s/source/target/
[*] $text =~ tr/set1/set2/

我把左边的$text想象成为vi中正在编辑的文本,=~想象成为vi中输入:,右边的/pattern/和s/source/target/则相当于在vi中输入的命令,这些命令就是对$text进行操作。以下perl代码用于提取url中的host:

#!/usr/bin/perl
$url = "http://www.chinaunix.net/download/index.html";
$url =~ /http:\/\/([^\/]+)/;
print "host = $1\n"

运行输出结果为:
www.chinaunix.net

$1代表第1个match的结果, 相当于你的代码中"function call()"

引用3
就我个人来说不愿意花太多时间去记一门语言的语法和关键词等等,因为已经要花很多时间来记 Unix 和 Emacs 的命令什么的了。只想轻松一点。
...
Ruby 不需要 {} 也不需要冒号,结尾用 end 表示。(其实这一点我不太喜欢,因为不是很一致,keyword 直接用 end 结尾,但另外一些却必须用 do 开始 end 结尾。)
同感,我希望能有一种脚本语言能够尽量接近C/C++的语法。

关于block
首先感谢你举的几个例子,现在我基本掌握了ruby的block语法。我有一个问题想请教你:能否把block看作是一个匿名的回调函数?

[ 本帖最后由 DennisRitchie 于 2007-8-22 23:07 编辑 ]

dz902 发表于 2007-08-23 00:29

原帖由 DennisRitchie 于 2007-8-23 01:04 发表 http://bbs.chinaunix.net/images/common/back.gif

有人能认真看并提出讨论真的是太开心了。


首先我没有完全理解你所讲的Symbol类,不知道Zend Engine的做法这么做是否和c++ stl中string的copy on write有类似的地方?

其次,在ruby语言中,变量有些情况下要加上:@等前缀(就像perl变量的$@%前缀),这么做虽然提高了效率,但是对于学习者来说却增加了负担,相对而言,python、php就比较"consistency"。


关于 Symbol 类的理解有几种办法:

按照『Everyday Scripting with Ruby』的说法其实一个 Symbol 就是一个什么方法都没有的 String。而这个实例的变量名称就是它的值。也就是 :book => 'book',:work => 'work'。

按照某个 Blog (忘掉了) 的精彩讲解,其实 Symbol 就是重复使用同一个 String 的办法。他给出了一个例子。例如有一个类似数据库的 Array Hash。


db = [ {'no' => 0, 'lang' => 'C'},
       {'no' => 1, 'lang' => 'PHP'},
       {'no' => 2, 'lang' => 'Ruby'}
       # and so on...
]


上面这样的用法,每次都会分配新的空间给 'no' 和 'lang',不但浪费了空间效率也会很低。当字符串用于表示一个变量的名字或者 key 的名字的时候,我们实际上完全不关心它们是不是属于同一个 copy,或者有什么方法等等。这个使用,用 Symbol 就解决这个问题了:


db = [ {:no => 0, :lang => 'C'},
       {:no => 1, :lang => 'PHP'},
       {:no => 2, :lang => 'Ruby'}
       # and so on...
]


这样的话,:no 和 :lang 虽然是字符串,但是并不会分配新的空间。

Zend Engine 的做法其实某种意义上就是 copy on write。

关于 sigil……自从 Perl 有了 sigil 这种东西,很多语言都开始模仿了。但是和 Perl/PHP 不同,Ruby 的 sigil 用于指示变量的作用域,而不是内容。而作用域这个东西是很抽象的,很难用其它的东西来描述,估计也是这个原因,所以 Ruby 并不支持 public attribute,所有成员变量不管是类的还是实例的,全部都只能内部访问,想外部访问必须经由 accessor。因为 Ruby 中的方法(也就是讯息传递)是不需要括号的(这点其实我也不太喜欢),所以如果允许外部访问成员变量,那么必然成员变量和方法是在同一个命名空间,当然这样就更一致了,但是命名空间就变小了,也将导致更复杂的概念问题(例如:block/variable/method/object 的区别云云)。

所以综上所述,Ruby 的设计理念不允许用 obj.attr 来访问 obj 的 attr 成员变量,所以的所以,在定义成员变量的时候,必须用某种方法来识别其作用域,最后,就采用 sigil 了。

上面虽然推论一堆,但是也是推论。但这里也有一个不一致的地方。那就是类方法用 ClassName.methodName 来定义,但是类变量却是 @@attr 来定义,当然这个不一致性也可以用上面的推论来说明。


我没有用过ruby,正在学习perl和python,按照我的猜测,应该是必须的。在Python中:

   [*] 变量不用申明
   [*] 简单变量可以直接使用
   [*] 复合变量(数组、链表、字典、用户自定义的类)必须先显示的创建,才可以使用他们


事实证明你的猜测是正确的。但是 Ruby 也提供了快捷方式 [] 和 {},还是算比较方便的。


我觉的把这行代码颠倒过来更容易理解,因为data是被操作的对象:



columns[:host] = data.match(/^http:\/\/([^\/]+)/)



非常感谢指出这个问题。一开始想到 RegExp,就直接奔那儿去了,确实这样比我哪个方法清晰多了。

另外感谢指教关于 =~ 的用法。因为 Unix 还不是太熟(vi 只看个两个命令,emacs 还在学),所以还不太习惯用这个东西,不过慢慢地应该就好了吧。


同感,我希望能有一种脚本语言能够尽量接近C/C++的语法。


其实按 PHP4 来说,应该是达到和 C/C++ 最接近的位置了。而 PHP5 更像 Java,连 interface 什么的都一律照搬了。不过其实最重要的是,Ruby/Python 这类语言虽然剑走偏锋,但是却给人一种很新颖的感觉:C-like 语法也是会有审美疲劳的,即使它是经典。所以,用 Ruby 也好,Python 也好,都很有意思。就如 Courier New 这种经典到不能再经典的字体偶尔也会用腻,我偶尔也会用自己做的等宽字体换换口味,呵,当然最后还是会换回来,因为它太经典了无法超越。


首先感谢你举的几个例子,现在我基本掌握了ruby的block语法。我有一个问题想请教你:能否把block看作是一个匿名的回调函数?


Ruby 中 block 和 callback/closure/first-class function 还是有一点点距离的……当然这个距离可以马上达到。Block 在 Ruby 中是和环境绑定的,所以你不能直接用 a = do ... end 这种办法。因为 block 是一个逻辑概念而不是语言实体。这里面没有 Block 对象的参加。实际上 Ruby 也没有所谓 Block 对象,而有 Proc 对象。这个可不是 Process (那是另外一个对象),而是 Proc(edure),也就是 Ruby 真正的「语言实体代码块」的实现。不管是包装 closure 还是用 callback/fcf,都可以:


a = Proc.new { puts "Hello, World!" }
a.call # prints Hello, World!


当然这个东西还有一个快捷方式,你用 Python 一定不会陌生:


a = lambda { puts "Hello, World!" }
a.call # prints Hello, World!


很惊喜吧。Ruby 更会让你惊喜的是,这个不但和 Python 很像,而且不限于单个 expression,可以是完整的函数,也可以返回值云云。当然参数还是用和 Smalltalk 类似的 |arg| 来获取。

上面两种还有一个不同是,在 lambda 中 return 将会 return 给使用这个函数的主儿,而 Proc.new 中的 return 则会 return 给所在的函数。如下所示:


def foo
    a = lambda {return "Spams and Eggs" }
    b = a.call
end

puts foo # Spams and Eggs


↑ a 返回给了 b。


def foo
    a = lambda {return "Spams and Eggs" }
    a.call
    "Good good study"
end

puts foo # Good good study


↑ a 返回给了「空」


def foo
    a = Proc.new {return "Spams and Eggs" }
    b = "Good good study" # never executed
end

puts foo # Spams and Eggs


↑ a 返回给了 foo

OVER,欢迎继续讨论~:mrgreen:

james.liu 发表于 2007-08-23 17:08

小mj。。。。我来了。。。

royalzhang 发表于 2007-08-24 15:45

支持一把。:em02: :em02: :em02: :em02: :em02:

DeceitLei 发表于 2007-08-29 15:22

很不错,我还是头一次认真的把一篇帖子从头看到尾,支持

fire9 发表于 2009-01-17 23:14

写的不错阿。赞一个!

lastexile 发表于 2009-04-05 11:55

这个学习帖子不错啊

暂时对ruby还是无爱 :em16:

redspider 发表于 2009-05-06 17:19

欣赏lz发帖的态度

shucho 发表于 2009-06-04 12:52

强大!

兰花仙子 发表于 2010-01-03 22:12

大概扫了一遍(俺承认没仔细看),如下:

columns = Hash.new
columns[:user_ip] = data

这里是没有必要用symbol作为hash的key的。
用普通的串即可,如:
columns['user_ip'] = data;

因为作用域的问题,这里不存在'user_ip'比:user_ip多耗内存的情况。
页: 1 [2] 3
查看完整版本: [学习]第一个 Ruby 程序 - 简易 Log 分析器