Ruby Ruby 的可变参数的 C 实现是怎样的?

towonzhou · 2014年02月21日 · 最后由 w_zengtao 回复于 2014年03月14日 · 6284 次阅读
本帖已被管理员设置为精华贴
def fun(*args)
  ........
end

args 是一个数组,请问这是怎么实现的?

这个是 Ruby 语言内置的呀,你是想了解 Ruby 底层是如何实现的么?

#1 楼 @lgn21st 恩,对啊。就 c 怎么实现的

#2 楼 @towonzhou 我自己没有深究过这部分的 C 代码是怎么实现的,但是这里不少人对 Ruby 的 C 实现有很深的研究。

#3 楼 @lgn21st 希望他们能看到,给菜鸟一点指引,,,,阿门

#4 楼 @towonzhou 那么你至少应该把标题改为:Ruby 的可变参数是的 C 实现是怎样的?

#5 楼 @lgn21st nod nod. 顺便请问一下 主键自增的 id 能设置为负数吗?会不会有什么影响?

楼主是想在 C 语言里实现可变参数吗?C 语言也有的。

#7 楼 @zhangyuan 只是想了解 ruby 是怎么实现的

参数都放到一个数组中,变成类似 int argc, VALUE* argv 的样子传递

10 楼 已删除

貌似和楼上的指引没啥关系,指引指的是 Native 方法的处理,参数个数限制在 -2- 15 个。

Ruby 处理很简单,在 c 里面已经将参数整理成 VALUE*argv 了,这个 VALUE 的类型就是 Array,传多少个都没有问题。

#9 楼 @luikore 怎么在不知道参数的个数的情况下放入一个数组中呢?也就是 argc 的值是怎么得到的。

#11 楼 @hhuai 我想问的就是在 c 里面是怎么处理成 VALUE *argv 的啊

咦..为啥这也是精华帖...

@luikore差不多的意思

C 中的 main 是这样的

int main(int argc, char *argv[]);

argc 是参数个数,argv 指向字符串数组,这里是把调用程序的名称也算进来的 例如 $ls 这个命令的 argc=1,argv[0] = "ls"

C~~是弱类型的语言,所以~~使用指针指向复杂的结构体,用来表达不同的类型。 在 C 语言眼里,万物都是数字,一个指针指向一块内存地址,代表各种可能,好单纯的语言。 结构体类似于面向对象编程语言中的对象。

可以看 ruby 里很多核心类的 C 实现,例如 Fixnum#to_s

static VALUE
fix_to_s(int argc, VALUE *argv, VALUE x)
{
    int base;

    if (argc == 0) base = 10;
    else {
        VALUE b;

        rb_scan_args(argc, argv, "01", &b);
        base = NUM2INT(b);
    }

    return rb_fix2str(x, base);
}

这里的 VALUE 可以看作代表 ruby 中的各种类型的结构体,argv 可以看作指向 VALUE 的数组,根据 argc 的值不同做处理就可以实现可变参数,默认参数值等功能。

@ruohanc问,为何这也精华帖了

edit at 2014-03-02 @rasefon 强弱类型的说法的确有很多误解,不如说是可以使用指针来干“坏事”的静态类型语言 http://stackoverflow.com/questions/430182/is-c-strongly-typed

C is a language that is statically typed but that has a lot of loopholes. One loophole is that you can freely cast any pointer type to any other pointer type.

#15 楼 @lingceng 可能是管理员手抖了一下,O(∩_∩)O

#13 楼 @towonzhou

这个应该在 Lexical Analysis 时得到的,看一下 parse.y 这里对于参数的处理

f_arg       : f_arg_item
            /*%c%*/
            /*%c
            {
            $$ = rb_ary_new3(1, $1);
            }
            c%*/
        | f_arg ',' f_arg_item
            {
            /*%%%*/
            $$ = $1;
            $$->nd_plen++;
            $$->nd_next = block_append($$->nd_next, $3->nd_next);
            rb_gc_force_recycle((VALUE)$3);
            /*%
            $$ = rb_ary_push($1, $3);
            %*/
            }
        ;

不管什么参数都是往 rb_ary 里扔。

C 语言本来就可以实现可变参数,比如 printf、scanf 之类的函数,参考这几个宏:va_arg, va_list, va_start, va_end

这也精华帖,是管理员手抖了么。。

#15 楼 @lingceng 大虾,,,这还是木有解释 argc 这个数是怎么得到的啊。如果已经得到了 argc 这个数肯定很简单....

#18 楼 @tsl0922 赞,需要的答案...

#19 楼 @towonzhou Linux 下你可以查看一下 exec 系列函数的用法,argc 之类的是程序执行时就已经确定了的。

require 'nokogiri'
str = '<a>1</a><a>2</a><a>3</a><a>4</a><a>5</a>'
doc = Nokogiri::HTML.parse(str)
links = doc.css("a")
puts links.each{|link|
}

这个为什么输出的是数字 0?不应该是 1 2 3 4 5 吗?

刚注册,不能发帖,所以在这里问问

python 里面,可变参数收集为元组,关键字参数收集为字典,ruby 里面应该也差不多吧。。。

#15 楼 @lingceng c 变成弱类型了……

#18 楼 @tsl0922 这头像怎么这么像 osc 里的一个.......

#26 楼 @iveryang 就是 osc 里的那个 😄

#22 楼 @ipooio require 'nokogiri'

str = '<a>1</a><a>2</a><a>3</a><a>4</a><a>5</a>'
doc = Nokogiri::HTML.parse(str)
links = doc.css("a")
links.each{|link|
   puts link
}

就可以了

#22 楼 @ipooio links 是 Nokogiri::XML::NodeSet 实例

Nokogiri::XML::NodeSet#each是这样的

# File lib/nokogiri/xml/node_set.rb, line 191
      def each(&block)
        0.upto(length - 1) do |x|
          yield self[x]
        end
      end

b = 0.upto(b) do |x| end

b 的值是 0, 所以你的代码输出的就是 0 了。 Nokogiri::XML::NodeSet#each加空block的返回值就是0

#24 楼 @pynix 不一样。ruby 没用元组。

#30 楼 @luikore 没有 tuple 实在是太蛋疼了

#32 楼 @bhuztez tuple 就是个不变长数组而已,命名访问还有 struct 呢

#33 楼 @luikore Erlang [{[{[{ Ruby [[[[[[ ... 只能眼花了

#34 楼 @bhuztez erlang 经常出现 [{[{[{ 的情况么?我基本没见过 ruby 有 [[[[[[

#35 楼 @luikore

比如 https://github.com/bhuztez/deepthought-ruby/blob/master/lib/deepthought.rb#L180

Ruby 的中间变量打出来完全没法看。数括号数到眼花,果然 Ruby 有 LISP 风范

#36 楼 @bhuztez 把函数调用的括号去掉一些就好些了,这加个空格也没差啊 [[ [[ [[

#37 楼 @luikore print 的出来的时候呢 ... 怎么调试啊 ... 回头来看就算分开也很乱么

#38 楼 @bhuztez 可以改 inspect 用缩进法打印嘛,难道 [{[{[{ 打出来也很好看?

#39 楼 @luikore 至少好认啊 { 一看就是个 tuple ... 都是 [ 谁知道这是干什么的 ...

不是很明白楼主想表达什么

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