Menu
CoddyTech

self trong phương thức

Thuộc phần Lập trình hướng đối tượng trong hành trình Ruby của Coddy. Bài học 9 trên 57.

Bên trong một phương thức, name = value luôn tạo một biến cục bộ, ngay cả khi lớp có phương thức setter name=. Để gọi setter, hãy viết rõ đối tượng nhận: 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

Đầu ra:

level is a new local variable here, still nil
2

Không cần self. khi đọc: level và self.level gọi cùng một phương thức. Theo cách viết thông thường, chỉ dùng self. khi Ruby yêu cầu, trước một setter:

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

Đầu ra:

24

Gọi setter từ initialize với self. giúp các đối tượng mới vượt qua cùng một bước kiểm tra như những thay đổi về sau, nhờ đó quy tắc chỉ nằm ở một nơi:

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

Đầu ra:

5
price must be positive

self là gì còn tùy vào nơi chạy đoạn code. Bên trong phương thức instance, nó là instance; trong thân lớp, bên ngoài mọi phương thức, nó chính là lớp:

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

Đầu ra:

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

Thử thách

Dễ

Lớp Account có phương thức setter tùy chỉnh balance=, phương thức này phát sinh ArgumentError với balance cannot be negative nếu giá trị nhỏ hơn 0. Hoàn thiện initialize(owner, balance), deposit(amount) và withdraw(amount) để mọi thay đổi của số dư đều đi qua setter đó bằng self., kể cả số dư ban đầu.

Code được cung cấp đọc tên chủ tài khoản và số dư ban đầu, sau đó đọc các lệnh +n (nạp tiền) hoặc -n (rút tiền). Code in ra Ada: 120 sau mỗi lệnh, hoặc in thông báo lỗi và số dư không đổi. Nếu số dư ban đầu không hợp lệ, code chỉ in thông báo lỗi.

Đặt code của bạn trong account.rb. main.rb chứa code đầu vào/đầu ra được cung cấp và không thể chỉnh sửa.

Tự làm thử

require_relative 'account'

# Đoạn code đầu vào/đầu ra đã được cung cấp: giữ nguyên
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 iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Ruby online