1

オブジェクトにインプレース メソッドを実装しようとすると、次のエラーが発生します。

Can't change the value of self (SyntaxError)

しようとするとき

self = map(&block)

次のオブジェクトで

class Node
  include Enumerable

  # binary tree representation
  attr_accessor :value, :left, :right
  def initialize(value=nil, left=nil, right=nil)
    @value, @left, @right = value, left, right
  end

  def map(&block)
    res = Array.new
    res << yield(value) if value
    res << left.map(&block) if left 
    res << right.map(&block) if right
    res.flatten
  end

  def map!(&block)
    self = self.map(&block)
  end

  def to_a
    map { |a| a }
  end
end

また、Enumerable の破壊的なメソッドのいくつかを無駄に使用しようとしました

map(&block).collect!

私のアプローチの何が問題で、このような機能をどのように実装しますか?

アップデート

アイデアを明確にするために、上記の map メソッドが正常に実行する二分木にマップを実装することです。私の問題は、そのメソッドをインプレース バージョンに変換することです。

irb(main):001:0> require './node.rb'
=> true
irb(main):002:0> root = @root = Node.new(1, Node.new(2, Node.new(3), Node.new(4)),Node.new(5, Node.new(6), Node.new(7)))
=> #<Node:0x78803f58 @value=1, @left=#<Node:0x78abc090 @value=2, @left=#<Node:0x78abc0f0 @value=3, @left=nil, @right=nil>, @right=#<Node:0x78abc0c0 @value=4, @left=nil, @right=nil>>, @right=#<Node:0x78803f88 @value=5, @left=#<Node:0x78abc060 @value=6, @left=nil, @right=nil>, @right=#<Node:0x78abc030 @value=7, @left=nil, @right=nil>>>
irb(main):003:0> root.map { |a| a * 3 }
=> [3, 6, 9, 12, 15, 18, 21]
irb(main):004:0> root
=> #<Node:0x778fb828 @value=1, @left=#<Node:0x778fb9c0 @value=2, @left=#<Node:0x778fba68 @value=3, @left=nil, @right=nil>, @right=#<Node:0x778fb9f0 @value=4, @left=nil, @right=nil>>, @right=#<Node:0x778fb888 @value=5, @left=#<Node:0x778fb930 @value=6, @left=nil, @right=nil>, @right=#<Node:0x778fb8b8 @value=7, @left=nil, @right=nil>>>
irb(main):005:0> root.map! { |a| a * 3 }
=> [3, 6, 9, 12, 15, 18, 21]]
irb(main):006:0> root
=> [3, 6, 9, 12, 15, 18, 21]
4

4 に答える 4

2

通常は次のように実装されます。

class Node

  attr_accessor :value, :left, :right

  def initialize_copy(source)
    super
    @value = @value.dup
    @left = @left.dup
    @right = @right.dup
  end

  def map(&block)
    dup.map!(&block)
  end

  def map!(&block)
    @value.map!(&block) if @value
    @left.map!(&block) if @left
    @right.map!(&block) if @right
    self
  end

end
于 2013-03-15T16:30:35.117 に答える
1

selfはキーワードであり、変数ではありません。そのため、割り当てを行うことはできません。

于 2013-03-15T20:39:52.327 に答える
0

このようなものはどうですか?

class Foo
  attr_accessor :bar

  def initialize(bar)
    @bar = bar
  end

  def update!
    self.instance_variables.each do |i| 
      self.instance_variable_set(i, yield(self.instance_variable_get(i)))
    end
  end
end
于 2013-03-15T16:59:25.153 に答える
0

Enumerable モジュールは、ドメイン固有のメソッドに基づいた一連のメソッドを提供しますeach。どのメソッドも破壊的ではありません。

代わりに、Enumerable を使用して独自のメソッドを定義します。

class Node

  # define each and include, or do it by hand to customize:

  Enumerable.instance_methods(false).each do |method|
    define_method(method) do |*args|
      # apply method to each instance variable
    end
  end

  %w( map reject etc.. ).each do |method|
    define_method("#{method}!") do |*args|
      results = send(method)
      # modify instance vars based on results
    end
  end

end
于 2013-03-15T17:23:31.817 に答える