【问题标题】:Splat (asterisk) operator on String字符串上的 Splat(星号)运算符
【发布时间】:2013-01-15 16:23:48
【问题描述】:

要编写 splat 运算符的自定义结果,必须实现 to_a 方法。 String 类的示例:

class String
  def to_a
    self.split //
  end
end

irb> res = *'text'
=> ["t", "e", "x", "t"]

但是没有上面的monkeypatch,String类对to_a方法一无所知:

irb> String.respond_to? :to_a
=> false

所以问题是,在标准的“未修补”字符串对象上应用 splat 运算符时会调用什么方法?

irb> res = *'text'
=> ['text']

【问题讨论】:

  • 不要用字符串覆盖*。它已被用作'a' * 2 => 'aa'。改变其行为会导致代码维护人员发疯。

标签: ruby monkeypatching


【解决方案1】:

首先:调用String.respond_to?(:to_a)不会告诉你字符串instance是否响应to_a,它会告诉你String是否类 响应to_a。如果你想知道一个字符串是否响应to_a,你必须问这个字符串:

'text'.respond_to?(:to_a) # => false

或者你可以询问String类是否有公共实例方法to_a:

String.public_instance_methods.include?(:to_a) # => false

现在,Strings 不回复to_a 的原因是因为不清楚你想要什么:你想要一个字符数组吗?字形的?线的?代码点?字节数?

a = *'text'.chars      # => ['a', 'b', 'c']
a = *'text'.codepoints # => [116, 101, 120, 116]
a = *'text'.bytes      # => [116, 101, 120, 116]
a = *'text'.lines      # => ['text']

至于为什么 splat 运算符的行为方式如您所见,这似乎是语言规范中的一个极端情况。我什至不能 100% 确定这是预期的行为。多重赋值规范运行了将近 4 页,详情请参阅 Ruby 语言规范的第 11.4.2.4 节。

【讨论】:

  • 它的目的是为了(非官方?)测试;)
  • 感谢有关类/实例方法调用的更正。只是写得太快了。
【解决方案2】:

Splat, by definition, returns the value in an array if the object doesn't respond to to_a:

it "assigns the splatted object contained into an array when the splatted object doesn't respond to to_a" do
  a = *1; a.should == [1]
end

警告:有点非官方,但相对可用。

【讨论】:

  • 谢谢,这解释了这个问题。我仍然发现 Ruby 有太多我喜欢的特殊情况。
  • @DavidUnric 在 Ruby 等相对有机的语言中通常是这种情况。我不确定我是否认为这是一种特殊情况或只是一种特定的默认行为。
【解决方案3】:

我不确定这是否足以满足您的需求,但您可以这样做:

1.9.3-p0 :008 > res = *'text'.chars
 => ["t", "e", "x", "t"]

【讨论】:

    猜你喜欢
    • 2018-07-20
    • 2013-08-04
    • 2018-05-14
    • 2013-07-04
    • 1970-01-01
    • 2017-07-09
    • 1970-01-01
    • 2018-12-08
    • 1970-01-01
    相关资源
    最近更新 更多