Могу ли я расширить встроенный класс String своими методами - PullRequest
1 голос
/ 14 мая 2019

Я считаю, что нет встроенного метода trim (strip) для удаления начальных и конечных пробелов из строк во встроенном классе String. Я хочу расширить его своими функциями. Является ли это возможным? Используя пример здесь , я попробовал следующий код:

String extend [
    trimleading: str [ |ch ret flag|
        ret := str.                 "make a copy of sent string"
        flag := true.
        [flag] whileTrue: [         "while first char is space"
            ch := ret first: 1.     "again test first char"
            ch = ' '                "check if space remaining" 
            ifTrue: [ ret := (ret copyFrom: 2 to: ret size)]    "copy from 2nd char"
            ifFalse: [flag := false] 
            ].
        ^ret                        "return modified string"
        ]
    trim: str [ |ret|
        ret := str. 
        ret := (self trimleading: ret).           "trim leading spaces"
        ret := (self trimleading: (ret reverse)). "reverse string and repeat trim leading"
        ^(ret reverse)                            "return re-reversed string"
        ]
].

oristr := '        this is a test  '
('>>',oristr,'<<') displayNl.
('>>',(oristr trim),'<<') displayNl.

вышеуказанный код не работает и выдает следующую ошибку:

$ gst string_extend_trim.st 

>>        this is a test  <<
Object: '        this is a test  ' error: did not understand #trim
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
String(Object)>>doesNotUnderstand: #trim (SysExcept.st:1448)
UndefinedObject>>executeStatements (string_extend_trim.st:23)

Где проблема и как ее можно исправить? Спасибо.

Редактировать: следующий код работает, но не меняет исходную строку:

String extend [
    trimleading [ |ch ret flag|
        ret := self.                    "make a copy of sent string"
        flag := true.
        [flag] whileTrue: [             "while first char is space"
            ch := ret first: 1.         "again test first char"
            ch = ' '                    "check if space remaining" 
            ifTrue: [ ret := (ret copyFrom: 2 to: ret size)]    "copy from 2nd char"
            ifFalse: [flag := false] 
            ].
        ^ret                                "return modified string"
        ]
    trim [ |ret|
        ret := self.    
        ret := (self trimleading).  "trim leading spaces"
        ret := ((ret reverse) trimleading ). "reverse string and repeat trim leading"
        ^(ret reverse)                      "return re-reverse string"
        ]
].

oristr := '        this is a test  '
('>>',oristr,'<<') displayNl.
('>>',(oristr trim),'<<') displayNl.
('>>',oristr,'<<') displayNl.
oristr := (oristr trim).
('>>',oristr,'<<') displayNl.

Как oristr trim может изменить oristr? Я не хочу писать oristr := oristr trim.

Ответы [ 2 ]

2 голосов
/ 14 мая 2019

Первая проблема, которую вы уже решили: изначально вы определили метод trim: с одним аргументом, но отправили trim без аргументов.

Вторая проблема - изменить строку на месте.Вы можете изменить символы с помощью self at: index put: aCharacter и некоторых других методов для копирования и перезаписи диапазонов, но вы не сможете изменить размер (длину) строки.В Smalltalks, я знаю, Объекты не могут изменить свой размер после того, как они были созданы.Поэтому я предлагаю вам заняться созданием новой строки с меньшим количеством символов в trim.

Существует метод обмена одного объекта на другой везде в Системе.Это называется become:.Но я думаю, что вы не должны использовать это здесь.В зависимости от реализации Smalltalk у вас могут возникнуть нежелательные побочные эффекты, такие как замена литерала String в методе (так что следующий вызов метода будет фактически выполняться с другой обрезанной строкой вместо литерала).

1 голос
/ 15 мая 2019

Разница между вашим кодом и примером, который вы связали, состоит в том, что в примере они расширяют пользовательский класс, но вы расширяете базовый класс.Разница в том, как вы должны загрузить свой код и запустить его.Вы должны использовать Packages в GNU-Smalltalk для его сборки.@Lurker дает отличный ответ на вопрос о том, как использовать расширенные классы в gst , пожалуйста, прочитайте его и добавьте комментарий, если вам это нравится, я не хочу дублировать информацию здесь.

Чтобы адаптировать ваш код к String extend:

String extend [
    trimleading: str [ |ch ret flag|
        ret := str.                     "make a copy of sent string"
        flag := true.
        [flag] whileTrue: [         "while first char is space"
            ch := ret first: 1.         "again test first char"
            ch = ' '
            ifTrue: [ ret := (ret copyFrom: 2 to: ret size) ]    "copy from 2nd char"
            ifFalse:  [flag := false ] 
        ].
        ^ ret                                "value is modified string"
    ]
    trim [ | ret |
        ret := self trimleading: self.           "trim leading spaces"
        ret := self trimleading: (ret copy reverse). "reverse string and repeat trim leading"
        ^ (ret reverse)                      "return re-reverse string"
    ]
].

oristr := '        this is a test  '.
('>>',oristr,'<<') displayNl.
('>>',(oristr trim),'<<') displayNl.
('>>',oristr,'<<') displayNl.
oristr := (oristr trim).
('>>',oristr,'<<') displayNl.

Вы отправляете сообщение #trim в origstr переменную, поэтому вы должны определить без каких-либо параметров.Однако это не относится к #trimleading:, поэтому я взял ваш предыдущий код и поместил его туда.

Примечание. Вы должны действительно прочитать о ключевом слове self, его действии и понять - выиспользуя это неправильно.Вы присваиваете значение ret := self, но не используете его, вы просто перезаписываете его следующим назначением.

...