- 论坛徽章:
- 0
|
原帖由 DennisRitchie 于 2007-8-23 01:04 发表 ![]()
有人能认真看并提出讨论真的是太开心了。
首先我没有完全理解你所讲的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[6]是被操作的对象:
- columns[:host] = data[6].match(/^http:\/\/([^\/]+)/)[1]
复制代码
非常感谢指出这个问题。一开始想到 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: |
|