Menu
CoddyTech

メソッド内のself

CoddyのRubyジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 9/57。

メソッドの中では、name = value は常にローカル変数を作成します。クラスにセッター name= があっても同じです。セッターを呼び出すには、レシーバーを記述します: self.name = value:

class Player
  attr_accessor :level

  def initialize
    @level = 1
  end

  def broken_level_up
    level = level + 1
  rescue NoMethodError
    puts "level is a new local variable here, still nil"
  end

  def level_up
    self.level = level + 1
  end
end

p1 = Player.new
p1.broken_level_up
p1.level_up
puts p1.level

出力:

level is a new local variable here, still nil
2

読み取りには self. は不要です。level と self.level は同じメソッドを呼び出します。一般的なスタイルでは、Rubyで必要な場合にだけ、セッターの前に self. を付けます。

class Rect
  attr_accessor :w, :h

  def initialize(w, h)
    @w = w
    @h = h
  end

  def area
    w * h
  end

  def double!
    self.w = w * 2
    self.h = self.h * 2
    self
  end
end

puts Rect.new(2, 3).double!.area

出力:

24

initializeからセッターをself.付きで呼び出すと、新しいオブジェクトにも後からの変更と同じチェックが適用されるため、ルールを一か所にまとめられます。

class Product
  attr_reader :price

  def initialize(price)
    self.price = price
  end

  def price=(value)
    raise ArgumentError, "price must be positive" if value <= 0

    @price = value
  end
end

puts Product.new(5).price
begin
  Product.new(0)
rescue ArgumentError => e
  puts e.message
end

出力:

5
price must be positive

self が何を指すかは、コードが実行される場所によって異なります。インスタンスメソッド内ではインスタンスを指し、クラス本体の中でどのメソッドの外にもある場合は、クラスそのものを指します。

class Robot
  puts "in the class body, self is #{self}"

  def whoami
    "in a method, self is a #{self.class}"
  end
end

puts Robot.new.whoami

出力:

in the class body, self is Robot
in a method, self is a Robot
challenge icon

チャレンジ

簡単

クラス Account には、0 未満の値に対して balance cannot be negative を伴う ArgumentError を発生させるカスタムセッター balance= があります。開始時の残高を含め、残高の変更がすべて self. を使ってこのセッターを通るように、initialize(owner, balance)、deposit(amount)、withdraw(amount) を完成させてください。

用意されたコードは、所有者と開始時の残高を読み取り、その後コマンド +n(入金)または -n(出金)を読み取ります。各コマンドの後に Ada: 120 を出力します。エラーが発生した場合は、エラーメッセージと変更されていない残高を出力します。無効な開始時の残高の場合は、エラーメッセージのみを出力します。

コードは account.rb に記述してください。main.rb には用意された入出力コードが含まれており、編集できません。

自分で試してみよう

require_relative 'account'

# 提供された入出力コード: そのままにしてください
input = []
while (line = gets)
  input << line.chomp
end
begin
  account = Account.new(input[0], input[1].to_i)
  input.drop(2).each do |cmd|
    begin
      amount = cmd[1..].to_i
      cmd.start_with?("+") ? account.deposit(amount) : account.withdraw(amount)
    rescue ArgumentError => e
      puts e.message
    end
    puts "#{account.owner}: #{account.balance}"
  end
rescue ArgumentError => e
  puts e.message
end
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Rubyオンラインコンパイラ