Способ реализации `String # split!` - PullRequest
3 голосов
/ 25 сентября 2010

Иногда мне нужен такой метод, который мог бы изменить класс своего объекта.Есть 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"]

Возможно ли это?Может быть, какие-нибудь крутые японские кунг-фу или некрасивые велосипеды - я бы хотел найти какое-нибудь решение.

Ответы [ 3 ]

10 голосов
/ 25 сентября 2010

Нет, не возможно.Объекты не могут менять свои классы в 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:, который разбивает строку на массив подстрок.Результат тот же: исходный строковый получатель теперь является массивом.

0 голосов
/ 29 сентября 2010

Это возможно только при использовании evil-ruby (по крайней мере, я уверен, что evil-ruby это поддерживает). Это действительно умный взлом, который подталкивает Ruby к тому, что он никогда не делал, но также и непереносимый взлом, который, как известно, вызывает реальные ошибки в коде Ruby, используя его. Вы не должны использовать его в производственном коде.

В противном случае, присвойте вашей строке внутренний массив и заставьте ее делегировать все сообщения в массив (вдоль строк BlankSlate + Forwardable ).

Это все еще не то, что я хотел бы сделать. Я не могу представить ситуацию, когда такое незначительное удобство перевешивает хакерскую реализацию.

0 голосов
/ 29 сентября 2010

Йорг W Миттаг ответ твердый.Это фундаментальный атрибут 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"]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...