Menu
Coddy logo textTech

self w metodach

Część sekcji Programowanie obiektowe ścieżki Ruby w Coddy. Lekcja 9 z 57.

Wewnątrz metody name = value zawsze tworzy zmienną lokalną, nawet jeśli klasa ma setter name=. Aby wywołać setter, zapisz odbiorcę: 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

Wynik:

level is a new local variable here, still nil
2

Odczytujące metody nie potrzebują self.: level i self.level wywołują tę samą metodę. Zwykle zapisuje się self. tylko tam, gdzie Ruby tego wymaga — przed metodą ustawiającą:

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

Wynik:

24

Wywołanie settera z initialize za pomocą self. sprawia, że nowe obiekty przechodzą tę samą kontrolę co późniejsze zmiany, dzięki czemu reguła jest określona w jednym miejscu:

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

Wynik:

5
price must be positive

To, czym jest self, zależy od tego, gdzie wykonywany jest kod. Wewnątrz metody instancji oznacza instancję; w ciele klasy, poza wszystkimi metodami, oznacza samą klasę:

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

Wynik:

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

Wyzwanie

Łatwy

Klasa Account ma niestandardowy setter balance=, który zgłasza ArgumentError z komunikatem balance cannot be negative dla wartości mniejszej niż 0. Uzupełnij initialize(owner, balance), deposit(amount) i withdraw(amount), tak aby każda zmiana salda przechodziła przez ten setter z użyciem self., także saldo początkowe.

Dostarczony kod odczytuje właściciela i saldo początkowe, a następnie polecenia +n (wpłata) lub -n (wypłata). Po każdym poleceniu wypisuje Ada: 120 albo komunikat o błędzie i niezmienione saldo. Nieprawidłowe saldo początkowe powoduje wypisanie tylko komunikatu o błędzie.

Umieść swój kod w pliku account.rb. Plik main.rb zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

require_relative 'account'

# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
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 iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Ruby online