瞎扯淡 Ruby 数组只是一种方法?

coooldfarmer · 2015年09月18日 · 最后由 mingyuan0715 回复于 2015年09月21日 · 3338 次阅读

C 里的标准数组定义是定长。但 ruby 里定义了 a[0],但也可以访问 a[50] ,但访问更多 a[100000] 进程可能会被 kill。所以我猜测 ruby 里的数组可能是一种方法?方法名就是 [],参数就是里面的下标。

对么

访问或赋值了 1 或者 10,就预分配 50 的位置。访问了 100,就预分配个 300 或 500 的位置?瞎唠叨的..

[] 的本身是一个方法名。http://ruby-doc.org/core-2.2.3/Array.html#method-i-5B-5D 访问的时候,会 check 这个下标是否在这个数组里面。

定义一个[]方法。

class A
  def [](index)
    "this is a [] method"
  end
end
A.new[1]  #=> "this is a [] method"
A.new["index"]  #=> "this is a [] method"

C 里面的数组和 ruby 里面的数组不是一种东西 ruby 里面数组是一个 object, 这个 object 本质上是 wrap 一个 C 的数组 [] 是 ruby 的 Array Class 的一个方法,不仅可以越界访问数组,还可以是负数。

VALUE
rb_ary_entry(VALUE ary, long offset)
{
    if (offset < 0) {
    offset += RARRAY_LEN(ary);  //如果是负数,就掰正
    }
    return rb_ary_elt(ary, offset);
}

static inline VALUE
rb_ary_elt(VALUE ary, long offset)
{
    long len = RARRAY_LEN(ary);
    if (len == 0) return Qnil; //如果数组为空,返回 nil
    if (offset < 0 || len <= offset) {
    return Qnil; //如果索引越界,返回 nil
    }
    return RARRAY_AREF(ary, offset);
}

array.c 里面的两个函数,根据索引访问数组的时候都是这两个函数处理的。

Ruby 经常被看做 Lisp 方言。所有的语句本质上都是消息传递(函数调用也是消息传递,所以本质上他们是一样的)。

主贴里的例子不贴切吧,在 C 里面我也可以越界访问下标啊

6 楼 已删除

访问 array[10000],会分配 10000 个内存占用,内存会爆掉。所以会 kill 掉。

#7 楼 @mingyuan0715 不可能,六十年代的机器也不会 array[10000] 就爆掉吧,我机器可以 array[10*9],array[10*10] 会抛出 RangeError,bignum too big to convert into 'long'

数组还真是一个方法

array = lambda{|x| x+1}
p array[0]  #=> 1

以上是声明一个自然数数组

#9 楼 @cicholgricenchos 我觉得你这个更多是解释了什么叫鸭子类型,因为你认为实现了下标读写器的类型就是数组,但无法说明数组就是方法。按照这种思路,数组的实现也可以是字典(所有的键是按数字从 0 开始递增),再如果我用链表实现,那么我也可以说数组就是链表。鸭子类型的强大之处就在于你可以专注于你可以做些什么事情,而无需过多担心你的对象到底是什么类型。

#8 楼 @africwildman 我的错,访问数组不会产生内存问题,赋值会。比如 a = [], a[1_000_000_000] = 1,内存就爆了。不过跟题主的问题无关。

我的试验结果是不会 kill 掉进程,但位数超过范围了会报错。例如,a[100000000000000000000000] ,RangeError: bignum too big to convert intolong'`

需要 登录 后方可回复, 如果你还没有账号请 注册新账号