【问题标题】:Optional argument in `File.read` with Ruby 1.9.2Ruby 1.9.2 中的“File.read”中的可选参数
【发布时间】:2014-02-05 11:14:08
【问题描述】:

根据docs,我相信下面使用 Ruby 1.9.2 的示例应该以与 Ruby 1.9.3 相同的方式工作,但事实并非如此。给定一个文件test,其内容为hello

Ruby 1.9.3p484:

File.read "test", 4, :mode => 'rb'
# => "HELL" 

红宝石 1.9.2p320

File.read "test", 4, :mode => 'rb'
# => TypeError: can't convert Hash into Integer

似乎 Ruby 1.9.2 和 1.9.3 在处理 File.read 的可选参数的方式上有所不同。为什么?我不知道它是在哪里声明的。

【问题讨论】:

  • FWIW,我无法重现这个(Ruby 1.9.3p286、i386-cygwin / Ruby 1.9.3p125、i386-mingw32)
  • @FrankSchmitt 我相信它必须在 1.9.2 上复制
  • @МалъСкрылевъ 你是对的,当然。显然,我有点困惑:-)
  • 我没有在任何地方安装 1.9.2 来确认,但我怀疑如果您在参数周围使用括号,问题就会消失。虽然括号是可选的,但它们非常重要,尤其是在处理多个参数时,尤其是在处理块时。我建议始终使用它们来消除任何歧义,但 YMMV。
  • @theTinMan 这不是语法或歧义问题。当用括号消除任何歧义时,我也可以重现这一点。仅仅,这似乎是从参数列表中正确解析选项哈希的问题。

标签: ruby file ruby-1.9.2


【解决方案1】:

如果您指定长度,Ruby 1.9.2 似乎也需要偏移量(在相关新闻中,我也可以在 1.9.2p320 上重现这一点,但不能在 1.9.3p484 上重现)。从文档和 C 代码中我不清楚为什么在 1.9.2 上需要这样做,但在这里应该不是太大的问题。

您可以将偏移量传递为nil,它可以在 1.9.3 和 1.9.2 上正常工作。

File.read "test", 4, nil, :mode => 'rb'

【讨论】:

  • 方法签名read(name, [length [, offset]], open_args)没有默认值,因此,为了传入open_args,之前的值必须在它们之前。 0 对于偏移量可能是可以接受的,因为 OP 想要从文件的开头读取。
  • 传入nil 或0 可能会起作用,但我更感兴趣的是为什么首先这是一个问题,以及为什么 它显然不在 1.9.3 中。这是 1.9.2 中的错误吗?
【解决方案2】:

补充 Holger Just 的回答。

源代码其实好像不一样。

Ruby 1.9.2

               static VALUE
rb_io_s_read(int argc, VALUE *argv, VALUE io)
{
    VALUE offset;
    struct foreach_arg arg;

    rb_scan_args(argc, argv, "13", NULL, NULL, &offset, NULL);
    open_key_args(argc, argv, &arg);
    if (NIL_P(arg.io)) return Qnil;
    if (!NIL_P(offset)) {
        struct seek_arg sarg;
        int state = 0;
        sarg.io = arg.io;
        sarg.offset = offset;
        sarg.mode = SEEK_SET;
        rb_protect(seek_before_access, (VALUE)&sarg, &state);
        if (state) {
            rb_io_close(arg.io);
            rb_jump_tag(state);
        }
        if (arg.argc == 2) arg.argc = 1;
    }
    return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
}

Ruby 1.9.3

               static VALUE
rb_io_s_read(int argc, VALUE *argv, VALUE io)
{
    VALUE opt, offset;
    struct foreach_arg arg;

    argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
    open_key_args(argc, argv, opt, &arg);
    if (NIL_P(arg.io)) return Qnil;
    if (!NIL_P(offset)) {
        struct seek_arg sarg;
        int state = 0;
        sarg.io = arg.io;
        sarg.offset = offset;
        sarg.mode = SEEK_SET;
        rb_protect(seek_before_access, (VALUE)&sarg, &state);
        if (state) {
            rb_io_close(arg.io);
            rb_jump_tag(state);
        }
        if (arg.argc == 2) arg.argc = 1;
    }
    return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
}

区别是:

所以它们实际上是不同的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-13
    • 2020-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多