免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: dz902
打印 上一主题 下一主题

[学习]第一个 Ruby 程序 - 简易 Log 分析器 [复制链接]

论坛徽章:
0
11 [报告]
发表于 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

  1. columns[:host] = /^http:\/\/([^\/]+)/.match(data[6])[1]
复制代码

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

  1. columns[:host] = data[6].match(/^http:\/\/([^\/]+)/)[1]
复制代码

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:

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

  5. 运行输出结果为:
  6. www.chinaunix.net
复制代码

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

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

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

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

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

论坛徽章:
0
12 [报告]
发表于 2007-08-23 00:29 |只看该作者
原帖由 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。


  1. db = [ {'no' => 0, 'lang' => 'C'},
  2.        {'no' => 1, 'lang' => 'PHP'},
  3.        {'no' => 2, 'lang' => 'Ruby'}
  4.        # and so on...
  5. ]
复制代码


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


  1. db = [ {:no => 0, :lang => 'C'},
  2.        {:no => 1, :lang => 'PHP'},
  3.        {:no => 2, :lang => 'Ruby'}
  4.        # and so on...
  5. ]
复制代码


这样的话,: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]是被操作的对象:



    1. 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,都可以:


    1. a = Proc.new { puts "Hello, World!" }
    2. a.call # prints Hello, World!
    复制代码


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


    1. a = lambda { puts "Hello, World!" }
    2. a.call # prints Hello, World!
    复制代码


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

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


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

    5. puts foo # Spams and Eggs
    复制代码


    ↑ a 返回给了 b。


    1. def foo
    2.     a = lambda {  return "Spams and Eggs" }
    3.     a.call
    4.     "Good good study"
    5. end

    6. puts foo # Good good study
    复制代码


    ↑ a 返回给了「空」


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

    5. puts foo # Spams and Eggs
    复制代码


    ↑ a 返回给了 foo

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

    论坛徽章:
    0
    13 [报告]
    发表于 2007-08-23 17:08 |只看该作者
    小mj。。。。我来了。。。

    论坛徽章:
    0
    14 [报告]
    发表于 2007-08-24 15:45 |只看该作者
    支持一把。

    论坛徽章:
    0
    15 [报告]
    发表于 2007-08-29 15:22 |只看该作者
    很不错,我还是头一次认真的把一篇帖子从头看到尾,支持

    论坛徽章:
    0
    16 [报告]
    发表于 2009-01-17 23:14 |只看该作者
    写的不错阿。赞一个!

    论坛徽章:
    0
    17 [报告]
    发表于 2009-04-05 11:55 |只看该作者
    这个学习帖子不错啊

    暂时对ruby还是无爱

    论坛徽章:
    0
    18 [报告]
    发表于 2009-05-06 17:19 |只看该作者
    欣赏lz发帖的态度

    论坛徽章:
    0
    19 [报告]
    发表于 2009-06-04 12:52 |只看该作者
    强大!

    论坛徽章:
    0
    20 [报告]
    发表于 2010-01-03 22:12 |只看该作者
    大概扫了一遍(俺承认没仔细看),如下:

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

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

    因为作用域的问题,这里不存在'user_ip'比:user_ip多耗内存的情况。
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP