[ruby-list:50846] Re: Stringの派生オブジェクトにsubを取った時のインスタンス変数のコピー
From:
Takefumi URA <ura.takefumi@...>
Date:
2019-11-21 17:50:56 UTC
List:
ruby-list #50846
浦です。
正木さん、お返事ありがとうございます。
一応subが新たなインスタンスを作ることは理解していたつもりです。
subが派生クラスのインスタンスを作ってくれるならインスタンス変数も
ケアしてほしかったなという思い込みでした。
なるほどsubをオーバーライドすればよかったですね。
…ただ非破壊系のメソッドを全部オーバーライドするのはちょっと骨かなあという気がします。
# ごめんなさいこの辺質問が足りませんでしたね
> 2019/11/22 2:32、MASAKI Haruka <yek@reasonset.net>のメール:
>
> 正木です。
>
> String#subは自身を返すわけではありませんから、
> 戻り値となっているオブジェクトはsubを呼び出したオブジェクトとは別物ですので、
> インスタンス変数は共有されません。
>
> サブクラスではなく、特異クラスを使った場合でも違うオブジェクトなので、
> 特異クラスは持っていない状態になります。
>
> #!ruby
> str = "Hello"
>
> class <<str
> @foo = "foo"
> def foo
> @foo
> end
> end
>
> str.foo # foo
> str2 = str.sub("foo", "bar")
> str2.foo # error
>
> varの値を継承したいなら次のようにするのはいかがでしょう。
>
> class NString < String
> #...
>
> def var=(val)
> @var = val
> end
>
> def sub
> new_nstr = super
> new_nstr.var = @val
> new_nstr
> end
> end
>
>
> On Fri, 22 Nov 2019 01:55:42 +0900
> Takefumi URA <ura.takefumi@gmail.com> wrote:
>
>> 浦といいます。
>>
>> Stringを派生させたクラスのオブジェクトにインスタンス変数を設定しました。
>> このオブジェクトにsubを適用してできたオブジェクトにはそのインスタンス
>> 変数がコピーされていませんでした。以下のような感じです。
>>
>>
>> $ cat test-string.rb
>> class NString < String
>> def initialize(s)
>> @var = s.hash # ハッシュ値を取ってるのは特に意味はない
>> super s
>> end
>>
>> def inspect
>> "#<NString:#{@var}:#{self}>"
>> end
>> end
>>
>> ns = NString.new('abc')
>> p ns # => #<NString:val:abc>
>> p ns.sub(/a/, 'A') # => #<NString::Abc>
>>
>> $ ruby -v test-string.rb
>> ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18]
>> #<NString:3775343761872790250:abc>
>> test-string.rb:8: warning: instance variable @var not initialized
>> #<NString::Abc>
>>
>> ご覧の通り @var が引き継がれておらず初期化もなされていません。
>> このあたり、インスタンス変数もケアしてくれる (subでcloneなりdupなりやってる)
>> のかなと思っていたので少し意外でした。
>>
>> Stringのソースを見てないのでなんともなんですけど、
>> subを取って新たなオブジェクトが得られた時 @var の値をコピーするにはどうしたらよいでしょうか?
>>
>> 別解としてsub!を使ってそもそもコピーする必要をなくすというのはあるでしょうけど
>> (というかそれでとりあえず解決しました)、純粋に疑問に思ったので質問してみることにしました。
>>