5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

crystalのシャローコピー、ディープコピーについて

Last updated at Posted at 2015-12-05

ブログからの転記です。

slack上でのcrystal-jaコミュニティで、いろんな議論(大体私からは不明点を聞くだけ)してるのですが、 ちょっとcyrstalで気になってたのが、シャローコピー、ディープコピーはどうするのか、というもの。

例えば、以下のコードはrubyだと


class ClassA
  attr_accessor :a
end

clsa = ClassA.new
clsa.a = 1
clsb = clsa.clone
clsb.a = 2
p clsb.a #=> 1
p clsa.a #=> 2

となります。 では、crystalではどうなるかというと


(同上)
p clsb.a #=> 2
p clsa.a #=> 2

となってしまいます。(attr_accessorはpropertyで読み替え)

どうもcyrstalでのやり方では、

を見る限りだと、「子クラスで override して使う前提」みたいです。 (@pine613さんの見立てでは) なので、ディープコピーの各クラスの実装例だと、以下のような感じになります。(同@pine613さんのコード)

class ClassA
  property :a

  def self.new 
    i = self.new 
    yield i
    i 
  end
     
  def clone 
    ClassA.new { |i|
      i.a = self.a
    }
  end
end 

因みにですが、crystalではStructクラスも用意されています。

classクラスとの違いは

を見ると

  • 構造体に対して new を実行するとヒープではなくスタック領域が割り当てられる
  • クラスが参照渡しであるのに対して、構造体は値渡しである
  • 構造体は暗黙的に Struct を継承し、Struct は Value を継承している。一方クラスは Reference を継承する

とあります。オブジェクト間で値をやり取りするようなことがあるなら、こっちを使うべき、という設計みたいですね。

@makenowjustさん曰く

「それと、 record マクロを使って定義した構造体には clone メソッドが定義されてます」
とのことで、実際に調べてみると以下のようになっています。

上記情報に従って書き直すと

struct ClassA
  property :a
end

record ClassA

classA = ClassA.new
classA.a = 1

classB = classA.clone
classB.a = 2

p classA.a #=> 1
p classB.a #=> 2

となり期待する動作になりました。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?