【问题标题】:A way to implement `String#split!`一种实现`String#split!`的方法
【发布时间】:2010-09-25 05:19:08
【问题描述】:

有时我需要这样的方法,它可以改变自己对象的类。有String#delete!#downcase!#encode!#gsub!#strip!#slice! 等。他们都在尝试更改字符串,但结果类仍然是String。我想要一种方法,可以将String 转换为Array。 一些方法来做到这一点:

irb(main):082:0> str = "qwerty"
=> "qwerty"
irb(main):083:0> str.split! "e"
=> ["qw", "rty"]
irb(main):084:0> str
=> ["qw", "rty"]

有可能吗?也许是一些很酷的日本功夫或丑陋的自行车——我希望看到任何解决方案。

【问题讨论】:

  • 显然可以写一个返回数组的方法,可惜不能就地修改

标签: ruby class self-modifying


【解决方案1】:

不,不可能。对象不能在 Ruby 中更改它们的类。

例如,在 Smalltalk 中,您可以使用 become:

becomeSubStrings: aString
    self become: (self subStrings: aString).

如果你这样称呼它:

s := 'qwerty'.
s becomeSubStrings: 'e'.

现在,s 是一个数组:

Transcript show: s printString.

结果是:

#('qw' 'rty')

从技术上讲,become: 不会更改对象的类,而是让一个对象成为另一个对象。在这种情况下,我们让self 成为self subStrings: 的结果,它将字符串拆分为子字符串数组。结果是一样的:原来的字符串接收者现在是一个数组。

【讨论】:

  • “我不知道,怎么解决”并不是不可能的保证,除非它没有更多的官方证明。
  • Nakilon:由于 Ruby 没有官方语言规范,您将 Ruby MRI 作为参考实现。并且 Ruby MRI 不支持更改对象的类。
  • @joschi:虽然没有指定 Ruby,例如Common Lisp 是,各种新的实现至少导致了 RubySpec:rubyspec.org
  • 是否有任何语言可以让对象更改其类?
  • @Andrew Grimm:在 Smalltalk 中,您可以使用 become:
【解决方案2】:

Jörg W Mittag 的回答是可靠的。这是 Ruby 作为一种语言的基本属性,您无法更改对象的类。

您能做的最好的事情就是重新分配变量,我确信您已经在这样做了:

irb(main):082:0> str = "qwerty"
=> "qwerty"
irb(main):083:0> str = str.split "e"
=> ["qw", "rty"]
irb(main):084:0> str
=> ["qw", "rty"]

【讨论】:

    【解决方案3】:

    只有使用evil-ruby 才能做到这一点(至少我很确定 evil-ruby 支持这一点)。这是一个非常聪明的 hack,它可以诱使 Ruby 做它从未打算做的事情,但也是一个不可移植的 hack,已知会在使用它的 Ruby 代码中导致实际的段错误。您绝对不应该在生产代码中使用它。

    否则,给你的字符串一个内部数组,让它将所有消息委托给数组(沿着BlankSlate + Forwardable 的行)。

    这仍然不是我想做的事情。我无法想象这样一种小便利超过了实现的骇人听闻的情况。

    【讨论】:

    • 这与 Firefox 类似:evil-ruby 是 MRI 扩展。即:它不是 Ruby,它是 C。它仅适用于 MRI,不适用于 YARV、JRuby、IronRuby、Rubinius、MacRuby、SmallRuby、MagLev、Cardinal、tinyrb、RubyGoLightly、BlueRuby、HotRuby、 Ruby Red、Red Sun、Ruby.NET、XRuby 或任何其他 Ruby 实现。基本上,你的意思是:“如果你给解释器打补丁,让它解释的语言不再是 Ruby,那么你就可以做到。”
    • 你对稳定性的看法是对的:evil-ruby 通过修改 MRI 的私有、内部、未记录、不稳定的实现细节来工作。由于这些不是公共 API 的一部分,而且通常甚至不是任何 API根本(公共或私有)的一部分,而只是附带的实现细节,因此即使在次要版本中,它们也可能以不兼容的方式更改(和甚至补丁版本)或通过小补丁(例如 Ruby 企业版),如果幸运的话,这会导致解释器以惊人的方式运行,如果没有,它只会导致程序无法预测地给出错误的答案。
    最近更新 更多