设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
楼主: DeathKing
打印 上一主题 下一主题

[讨论] Ruby/RGSS Tips 每日一更 [技术区的版聊帖?]

  [复制链接]

Lv1.梦旅人

梦石
0
星屑
110
在线时间
953 小时
注册时间
2007-4-25
帖子
805
64
发表于 2010-12-23 06:33:26 | 只看该作者
本帖最后由 苏小脉 于 2010-12-24 03:56 编辑

字符串扣留

 先从一个 Ruby 实例看起:

p "hello".object_id, "hello".object_id

  object_id 可以获取一个对象的唯一标识,而这行代码打印出了不同的 ID,说明两次引用的字符串字面值生成了两个不同的字符串对象,但它们的内容是一致的。这在面向对象语言中是一个普遍的现象,在某些场合下可能会引起以下问题:

   1. 当频繁使用 Ruby 的字面值指定某个字符串时,每次通过 Ruby 的字面值指定的字符串都会生成一个新的对象,长此以往就会产生大量的内容相同的字符串对象。这种空间的浪费意味着不必要的数据占用了更多的 Cache 和内存,减少了其它资源利用 Cache 的机会,也同时增加了内存分配和回收的复杂度;
   2. 我们经常需要比较字符串是否相等(如散列表的键值比较),而无论是什么语言,底层的实现方法也无非是调用 memcmp、strcmp 之类的函数来比较内存,理论上这个过程需要 O(n) 的时间(n = 字符串长度),而如果这样的比较需要频繁进行,那代价也是不容忽视的。

  当今不少高级语言中,都内置一种被称为“扣留”(Intern)的机制,它解决了这一难题。它的思想是:使用一个全局的字符串常量池来管理字符串,每次准备分配新的字符串对象之前,程序都会先检查内容相同的字符串对象是否已经被“扣留”在了常量池中,若是,则不分配新的对象,直接引用常量池中的对象;若不是则分配新的对象,并“扣留”在常量池中。这当然增加了字符串对象构造时的时间,但却解决了上述两种情况下的空间(没有产生字符串的克隆)和时间(逐字节比较字符串变为了指针相等的判断)效率问题。

  这个机制最早由 Lisp 用来管理符号,后来也被 Python(intern(string))、Java(String#intern)、.NET(String.intern) 等语言继承,用来实现字符串的扣留。Ruby 通过符号表实现了符号对象的扣留机制,但内置的字符串对象并没有扣留。Ruby 的 String#intern 方法看似扣留,实则是把一个已有的字符串对象转换为符号对象。使用这个方法并不会节省内存,只能起到简化字符串比较的时间复杂度的作用。所以,在 Ruby 中,操作常量的字符串并处于上述两种情况时应该尽量使用符号而不是字符串。Ruby 1.9 的新 Hash 字面值支持一种更简洁的符号键语法糖,其设计目的就是为了推荐用户使用符号而不是字符串。

http://szsu.wordpress.com/2010/09/21/string_intern/

点评

立即值概念不同,立即值并不是真正物理存在的 Ruby 对象,只存在于 Ruby 逻辑层面上。相同的是这些值和符号一样都是常量,是不可变的(Immutable)。  发表于 2010-12-27 00:58
貌似某书上写符号和整数为【立即值】,特性之一为不能定义单例方法,看起来好像和这个扣留机制有点关系么  发表于 2010-12-27 00:23
Java 也有这样的机制的说. 以前有一次写 Java 程序的时候就犯过这类的错误. 两个不相等的同字符串~  发表于 2010-12-23 09:07
[email protected]:~> repeat 1 fortune
Matz is nice, so we are nice.
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1040
在线时间
1564 小时
注册时间
2008-7-30
帖子
4418

贵宾

63
 楼主| 发表于 2010-11-28 13:17:10 | 只看该作者
( Dave Thomas && Matz ) @ Ruby Conf 2010








DeathKing于2010-12-11 17:30补充以下内容:
给新手的String类参考手册:http://rpg.blue/thread-162871-1-1.html

See FScript Here:https://github.com/DeathKing/fscript
潜心编写URG3中。
所有对URG3的疑问和勘误或者建议,请移步至发布页面。
欢迎萌妹纸催更
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
110
在线时间
953 小时
注册时间
2007-4-25
帖子
805
62
发表于 2010-11-18 06:56:30 | 只看该作者
本帖最后由 苏小脉 于 2010-11-18 06:57 编辑

The great ruby shootout:
http://programmingzen.com/2010/0 ... shootout-july-2010/

这是一个由来自 IBM 的软件工程师 Antonio Cangiano 执行的 benchmark,其结果展示了不同 Ruby 的实现在 Linux 和 Windows 上的不同性能。

官方版的 Ruby 实现(CRuby)开发环境是 Linux,优化时针对 Linux 的多,针对 Windows NT 的少,再加上编译器优化性能的差异(GCC <=> MSVC),使得 Linux 下的 CRuby 性能整体高于 Windows。

在 Linux 下,平均最快的实现似乎是 基于 YARV 虚拟机的 Ruby 1.9.2(即 CRuby 的最新稳定 Release),基于 Sun JVM 的 JRuby 紧随其后;Windows 下,JRuby 的性能胜过了 Ruby 1.9.2。

MagLev 和 Rubinius 是这前两名巨头最大的竞争对手,现在仍在快速发展。特别值得一提的是 Rubinius,其最新的 1.1 版本在 JIT 优化和 GIL 性能上又有了提升,相信她在下一次 shootout 会有杰出的表现。

东风吹,战鼓擂,当今世界谁怕谁。革命仍未成功,阶级斗争还在继续。

点评

怎么个无视法呢?  发表于 2010-11-19 07:16
Rubinius 的优化好可爱,见到的一个简单的例子就是把 nil 给无视掉 O_O  发表于 2010-11-18 22:32
[email protected]:~> repeat 1 fortune
Matz is nice, so we are nice.
回复 支持 反对

使用道具 举报

Lv2.观梦者 (管理员)

八云紫的式神

梦石
0
星屑
539
在线时间
1238 小时
注册时间
2008-1-1
帖子
4282

烫烫烫

61
发表于 2010-11-17 16:19:31 | 只看该作者
逻辑表达式

Ruby把nil和false认为逻辑假,其余任何对象认为逻辑真

if 0
  print "0 is true"
else
  print "0 is false"
end

这在其他语言里一般会得到 0 is false,但是在Ruby里是 0 is true

可以利用这个特性来做一些有趣的简写

while line = gets
  print line
end

会把标准输入一行行打印出来,直到文件尾


由于if不一定必须为true和false,而是可以使用任何对象,所以逻辑运算符也不会强制返回逻辑值,而是返回第一个决定逻辑值的对象


true and nil #=>nil
1 and "a" #=>"a"
false and true #=> false
false or nil #=> nil
&& 和 || 也有这一特性

比较常用的有个||=运算符,可以用来代替 a = x if a这样的语句

hash = {a: "b"}
hash[:a] ||= "c"
在想修改hash或数组的值,但是不确定那个键是否存在,并不想因此额外增加长度时使用
rm for linux(wine)制作中,期待夏娜SAMA能实现到webrm上
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1040
在线时间
1564 小时
注册时间
2008-7-30
帖子
4418

贵宾

60
 楼主| 发表于 2010-11-16 23:17:21 | 只看该作者
本帖最后由 DeathKing 于 2010-11-16 23:18 编辑

一些小问题
  1. def f(n)
  2.   if n == 1
  3.     return 1
  4.   else
  5.     return n * f(n - 1)
  6.   end
  7. end

  8. f(1_000_000)
复制代码
看上去是计算1,000,000的阶乘,实际呢?这种递归运算当到达一定的堆栈深度时会被停止,引发stack level too deep异常而中止。
  1. SystemStackError: stack level too deep
  2.         from (irb):21:in `f'
  3. ... 7656 levels...
复制代码
进行了7656层,在1.8.6中,我的机器只能进行1479层。所以要合理使用递归,关注堆栈深度。



只做抛砖引玉,请讨论更深入的问题

点评

CRuby现在还没有尾调用优化;对于高级的编译器来说,递归阶乘是典型的尾递归,可完美优化为等价的循环。  发表于 2010-11-17 01:38
优化时可以权衡轻重,是否值得为了效率而牺牲时间寻找非递归的途径。  发表于 2010-11-17 01:38

See FScript Here:https://github.com/DeathKing/fscript
潜心编写URG3中。
所有对URG3的疑问和勘误或者建议,请移步至发布页面。
欢迎萌妹纸催更
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1040
在线时间
1564 小时
注册时间
2008-7-30
帖子
4418

贵宾

59
 楼主| 发表于 2010-11-12 18:19:00 | 只看该作者
本帖最后由 DeathKing 于 2010-11-12 18:19 编辑

ri,一个很好的帮手,不过需要安装了Ruby,因为他是有Dave Thomas(《Programming Ruby》的作者之一)设计的工具。
  1. Usage: ri.bat [options] [names...]
复制代码
查询一下Net::POP3如何使用,有点像是man?真是意外的详细
  1. C:\Documents and Settings\DeathKing>ri Net::POP3
  2. -------------------------------------------- Class: Net::POP3 < Protocol

  3. NET::POP3
  4. =========


  5. What is This Library?
  6. ---------------------

  7.      This library provides functionality for retrieving email via POP3,
  8.      the Post Office Protocol version 3. For details of POP3, see
  9.      [RFC1939] (http://www.ietf.org/rfc/rfc1939.txt).


  10. Examples
  11. --------

  12.      Retrieving Messages

  13.      This example retrieves messages from the server and deletes them on
  14.      the server.

  15.      Messages are written to files named 'inbox/1', 'inbox/2', ....
  16.      Replace 'pop.example.com' with your POP3 server address, and
  17.      'YourAccount' and 'YourPassword' with the appropriate account
  18.      details.

  19.          require 'net/pop'

  20.          pop = Net::POP3.new('pop.example.com')
  21.          pop.start('YourAccount', 'YourPassword')             # (1)
  22.          if pop.mails.empty?
  23.            puts 'No mail.'
  24.          else
  25.            i = 0
  26.            pop.each_mail do |m|   # or "pop.mails.each ..."   # (2)
  27.              File.open("inbox/#{i}", 'w') do |f|
  28.                f.write m.pop
  29.              end
  30.              m.delete
  31.              i += 1
  32.            end
  33.            puts "#{pop.mails.size} mails popped."
  34.          end
  35.          pop.finish                                           # (3)

  36.      1.  Call Net::POP3#start and start POP session.

  37.      2.  Access messages by using POP3#each_mail and/or POP3#mails.

  38.      3.  Close POP session by calling POP3#finish or use the block form
  39.          of #start.

  40.      Shortened Code

  41.      The example above is very verbose. You can shorten the code by
  42.      using some utility methods. First, the block form of
  43.      Net::POP3.start can be used instead of POP3.new, POP3#start and
  44.      POP3#finish.

  45.          require 'net/pop'

  46.          Net::POP3.start('pop.example.com', 110,
  47.                          'YourAccount', 'YourPassword') do |pop|
  48.            if pop.mails.empty?
  49.              puts 'No mail.'
  50.            else
  51.              i = 0
  52.              pop.each_mail do |m|   # or "pop.mails.each ..."
  53.                File.open("inbox/#{i}", 'w') do |f|
  54.                  f.write m.pop
  55.                end
  56.                m.delete
  57.                i += 1
  58.              end
  59.              puts "#{pop.mails.size} mails popped."
  60.            end
  61.          end

  62.      POP3#delete_all is an alternative for #each_mail and #delete.

  63.          require 'net/pop'

  64.          Net::POP3.start('pop.example.com', 110,
  65.                          'YourAccount', 'YourPassword') do |pop|
  66.            if pop.mails.empty?
  67.              puts 'No mail.'
  68.            else
  69.              i = 1
  70.              pop.delete_all do |m|
  71.                File.open("inbox/#{i}", 'w') do |f|
  72.                  f.write m.pop
  73.                end
  74.                i += 1
  75.              end
  76.            end
  77.          end

  78.      And here is an even shorter example.

  79.          require 'net/pop'

  80.          i = 0
  81.          Net::POP3.delete_all('pop.example.com', 110,
  82.                               'YourAccount', 'YourPassword') do |m|
  83.            File.open("inbox/#{i}", 'w') do |f|
  84.              f.write m.pop
  85.            end
  86.            i += 1
  87.          end

  88.      Memory Space Issues

  89.      All the examples above get each message as one big string. This
  90.      example avoids this.

  91.          require 'net/pop'

  92.          i = 1
  93.          Net::POP3.delete_all('pop.example.com', 110,
  94.                               'YourAccount', 'YourPassword') do |m|
  95.            File.open("inbox/#{i}", 'w') do |f|
  96.              m.pop do |chunk|    # get a message little by little.
  97.                f.write chunk
  98.              end
  99.              i += 1
  100.            end
  101.          end

  102.      Using APOP

  103.      The net/pop library supports APOP authentication. To use APOP, use
  104.      the Net::APOP class instead of the Net::POP3 class. You can use the
  105.      utility method, Net::POP3.APOP(). For example:

  106.          require 'net/pop'

  107.          # Use APOP authentication if $isapop == true
  108.          pop = Net::POP3.APOP($is_apop).new('apop.example.com', 110)
  109.          pop.start(YourAccount', 'YourPassword') do |pop|
  110.            # Rest of the code is the same.
  111.          end

  112.      Fetch Only Selected Mail Using 'UIDL' POP Command

  113.      If your POP server provides UIDL functionality, you can grab only
  114.      selected mails from the POP server. e.g.

  115.          def need_pop?( id )
  116.            # determine if we need pop this mail...
  117.          end

  118.          Net::POP3.start('pop.example.com', 110,
  119.                          'Your account', 'Your password') do |pop|
  120.            pop.mails.select { |m| need_pop?(m.unique_id) }.each do |m|
  121.              do_something(m.pop)
  122.            end
  123.          end

  124.      The POPMail#unique_id() method returns the unique-id of the message
  125.      as a String. Normally the unique-id is a hash of the message.

  126. ------------------------------------------------------------------------


  127. Constants:
  128. ----------

  129.      Revision = %q$Revision: 19776 $.split[1]


  130. Attributes:
  131. -----------

  132.      address (R):
  133.           The address to connect to.

  134.      open_timeout (RW):
  135.           Seconds to wait until a connection is opened. If the POP3
  136.           object cannot open a connection within this time, it raises a
  137.           TimeoutError exception.

  138.      read_timeout (R):
  139.           Seconds to wait until reading one block (by one read(1) call).
  140.           If the POP3 object cannot complete a read() within this time,
  141.           it raises a TimeoutError exception.



  142. Class methods:
  143. --------------

  144.      APOP, auth_only, certs, create_ssl_params, default_pop3_port,
  145.      default_pop3s_port, default_port, delete_all, disable_ssl,
  146.      enable_ssl, foreach, new, ssl_params, start, use_ssl?, verify


  147. Instance methods:
  148. -----------------

  149.      active?, apop?, auth_only, command, delete_all, disable_ssl,
  150.      do_finish, do_start, each, each_mail, enable_ssl, finish, inspect,
  151.      logging, mails, n_bytes, n_mails, on_connect, port, read_timeout=,
  152.      reset, set_debug_output, start, started?, use_ssl?
复制代码

See FScript Here:https://github.com/DeathKing/fscript
潜心编写URG3中。
所有对URG3的疑问和勘误或者建议,请移步至发布页面。
欢迎萌妹纸催更
回复 支持 反对

使用道具 举报

Lv2.观梦者

傻♂逼

梦石
0
星屑
369
在线时间
1605 小时
注册时间
2007-3-13
帖子
6562

烫烫烫开拓者

58
发表于 2010-11-9 19:20:13 | 只看该作者
你要相信,Ruby可以像很多脚本语言一样抽插在各种软件当中……实现起来非常简单,只要编译一下……

点评

编译的方法是“百度谷歌雅虎优先搜索算法”  发表于 2010-11-9 19:23
哎呀,蛋疼什么的最有爱了
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1040
在线时间
1564 小时
注册时间
2008-7-30
帖子
4418

贵宾

57
 楼主| 发表于 2010-11-7 08:26:42 | 只看该作者
本帖最后由 DeathKing 于 2010-11-7 08:27 编辑

像打开普通文件那样打开网页,open-uri是个好工具:
  1. require 'open-uri.rb'
  2. open("http://rpg.blue") do |f|
  3.   f.each_line do |line|
  4.     p line
  5.   end
  6. end
复制代码
为了获得更好的效果,最好先将KCODE设置为UTF-8
  1. $KCODE = 'u'
复制代码


一些参考:
1,http://www.kuqin.com/rubycndocument/man/addlib/open-uri.html
2,http://fireflyman.javaeye.com/blog/671898

点评

warning: variable $KCODE is no longer effective; ignored  发表于 2010-11-7 09:04
KCODE已经废弃,对它赋值会得到一个warning  发表于 2010-11-7 09:04

See FScript Here:https://github.com/DeathKing/fscript
潜心编写URG3中。
所有对URG3的疑问和勘误或者建议,请移步至发布页面。
欢迎萌妹纸催更
回复 支持 反对

使用道具 举报

Lv2.观梦者 (管理员)

八云紫的式神

梦石
0
星屑
539
在线时间
1238 小时
注册时间
2008-1-1
帖子
4282

烫烫烫

56
发表于 2010-11-3 16:22:25 | 只看该作者
与c等语言不同,ruby的整数大小没有限制,超过特定值后会自动变成Bignum

点评

换个说法:弱类型是在对某个对象进行操作的时候不检查类型,而强类型是必须检查类型才能成功执行。Ruby 的 duck typing 则是需要通过动态判断类型的  发表于 2010-11-4 21:01
超过50%以上的人认为 C 是弱类型,因为 C 的大部分数据类型可以进行隐式类型转换。  发表于 2010-11-4 20:58
弱类型是指可以隐式转换数据类型,Ruby 的 duck typing 并非隐式转换,你还是没弄清楚弱类型和动态类型的区别。动态类型语言,变量是没有类型的。  发表于 2010-11-4 20:56
a = 1 p a #=> 1 a = "1" p a #=> "1" 这个在强类型语言里是做不到的  发表于 2010-11-4 20:49
那么变量就只能指C底层的变量了...C是弱类型吗=.=  发表于 2010-11-4 20:46
rm for linux(wine)制作中,期待夏娜SAMA能实现到webrm上
回复 支持 反对

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

梦石
0
星屑
50
在线时间
21 小时
注册时间
2007-7-3
帖子
573
55
发表于 2010-11-1 11:34:49 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-4-20 09:47

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表