cv.cm

Lập trình · Ngôn ngữ lập trình

Hướng dẫn học lập trình Ruby cơ bản cho người mới

7 phút đọc

Trả lời nhanh

Ruby là ngôn ngữ kịch bản động, hướng đối tượng, được thiết kế để đọc và viết dễ chịu. Lưu puts "Hello, world" vào hello.rb rồi chạy ruby hello.rb. Mọi thứ trong Ruby đều là đối tượng, kể cả số và nil. Các ý tưởng cốt lõi là phương thức định nghĩa bằng def, mảng và hash, block truyền cho các iterator như each và map, lớp và module, cùng ngoại lệ xử lý bằng begin/rescue.

Mở Kiểm tra regex

Ruby là gì và dùng để làm gì

Ruby do Yukihiro Matsumoto ("Matz") tạo ra tại Nhật Bản và phát hành lần đầu năm 1995, với mục tiêu làm cho lập trình viên hạnh phúc. Ruby nổi tiếng nhờ Ruby on Rails, framework web đứng sau các trang như GitHub và Shopify. Ruby được dùng cho ứng dụng web, viết script, tự động hóa và các công cụ cho lập trình viên như Homebrew và CocoaPods. Bản triển khai tiêu chuẩn là CRuby (còn gọi là MRI).

Cài Ruby và chạy Hello, world

macOS và nhiều hệ thống Linux đã có sẵn Ruby, nhưng thường là bản cũ; hãy cài Ruby 3 mới bằng trình quản lý phiên bản như rbenv, asdf hoặc mise, hoặc dùng RubyInstaller trên Windows. Kiểm tra bằng ruby -v.

puts "Hello, world"
ruby hello.rb
# Hello, world
irb          # interactive Ruby shell

puts in một giá trị kèm ký tự xuống dòng. Dấu ngoặc quanh đối số của phương thức là tùy chọn khi ý nghĩa đã rõ.

Biến và các kiểu dữ liệu cơ bản

Biến không cần khai báo và có thể chứa bất kỳ đối tượng nào. Theo quy ước, tên dùng snake_case. Hằng số bắt đầu bằng chữ cái viết hoa.

LớpVí dụGhi chú
Integer42, 2**100Kích thước bất kỳ
Float3.14Độ chính xác kép
String"hi #{name}", 'hi'Có thể thay đổi; dấu nháy kép nội suy biến
Symbol:nameĐịnh danh bất biến, thường dùng làm khóa hash
true, falsetrueChỉ false và nil được coi là sai
NilClassnilKhông có giá trị
Array, Hash[1, 2], {a: 1}Các collection dựng sẵn
name = "Ada"
count = 7
puts "#{name} has #{count} items"   # Ada has 7 items
puts count / 2, count / 2.0         # 3, then 3.5
puts "12".to_i + 1                  # 13
puts 5.class, nil.to_a.inspect      # Integer, then []
puts 0 ? "0 is truthy" : "falsy"    # 0 is truthy

Điều khiển luồng

score = 72
if score >= 90
  puts "A"
elsif score >= 70
  puts "B"          # B
else
  puts "C"
end

puts "pass" unless score < 50    # statement modifier

3.times { |i| print i, " " }     # 0 1 2
puts

n = 10
n /= 2 while n > 1
puts n                           # 1

kind = case "SAT"
       when "SAT", "SUN" then "weekend"
       else "weekday"
       end
puts kind                        # weekend

Các khối kết thúc bằng end thay vì dấu ngoặc nhọn. Mã Ruby thường được thụt lề 2 dấu cách.

Phương thức

Phương thức trả về giá trị của biểu thức cuối cùng, nên return thường không cần thiết. Theo quy ước, phương thức trả về boolean kết thúc bằng ?, còn phương thức thay đổi trực tiếp đối tượng nhận kết thúc bằng !.

def greet(name, greeting: "Hello")
  "#{greeting}, #{name}!"
end

def total(*nums)
  nums.sum
end

puts greet("Lin")                   # Hello, Lin!
puts greet("Lin", greeting: "Hi")   # Hi, Lin!
puts total(1, 2, 3)                 # 6
puts 4.even?, "abc".upcase          # true, then ABC

s = "hello"
s.upcase!          # modifies s in place
puts s             # HELLO

Mảng và hash

nums = [3, 1, 2]
nums << 5
p nums.sort, nums.first, nums.last   # [1, 2, 3, 5] then 3 then 5
p nums.sort[1..2]                    # [2, 3]

ages = { "ann" => 31, "bob" => 25 }
ages["cy"] = 40
ages.each { |person, age| puts "#{person} is #{age}" }
p ages.fetch("zed", 0)               # 0

user = { name: "Ann", city: "Oslo" } # symbol keys
p user[:name]                        # "Ann"

p in dạng inspect của giá trị, rất tiện khi gỡ lỗi vì hiển thị cả dấu nháy và dấu ngoặc.

Tính năng đặc trưng: block và iterator

Block là một đoạn mã được truyền cho phương thức, viết bằng { ... } trên một dòng hoặc do ... end trên nhiều dòng. Ruby lặp chủ yếu qua block thay vì vòng lặp for, và các phương thức của Enumerable giúp biến đổi dữ liệu rất gọn.

nums = [1, 2, 3, 4, 5]
p nums.map { |n| n * n }               # [1, 4, 9, 16, 25]
p nums.select(&:even?)                 # [2, 4]
p nums.reduce(0) { |sum, n| sum + n }  # 15
p nums.each_slice(2).to_a              # [[1, 2], [3, 4], [5]]
p %w[pear fig apple].sort_by(&:length) # ["fig", "pear", "apple"]

def twice
  yield
  yield
end
twice { puts "hi" }   # prints hi two times

&:even? là cách viết tắt của { |n| n.even? }. Phương thức do bạn viết nhận một block và gọi nó bằng yield.

Lớp và module

module Greeter
  def hello
    "Hello from #{name}"
  end
end

class Account
  include Greeter          # mix in module methods
  attr_reader :name, :balance

  def initialize(name)
    @name = name           # @ marks an instance variable
    @balance = 0
  end

  def deposit(amount)
    raise ArgumentError, "amount must be positive" unless amount.positive?
    @balance += amount
    self
  end

  def to_s = "#{name}: #{balance}"
end

acc = Account.new("Ann")
acc.deposit(30).deposit(20)
puts acc        # Ann: 50
puts acc.hello  # Hello from Ann

attr_reader tạo ra các phương thức getter. Module gom các phương thức để có thể trộn (mix in) vào nhiều lớp, đây là cách Ruby thay cho đa kế thừa. Dạng một dòng def to_s = ... cần Ruby 3.0 trở lên.

Xử lý lỗi

def parse_age(text)
  age = Integer(text)       # raises ArgumentError on bad input
  raise ArgumentError, "negative age" if age.negative?
  age
end

begin
  puts parse_age("41")      # 41
  puts parse_age("abc")
rescue ArgumentError => e
  puts "error: #{e.message}"  # error: invalid value for Integer(): "abc"
ensure
  puts "done"
end

rescue bắt ngoại lệ, còn ensure luôn được chạy. Bên trong một phương thức, bạn có thể viết rescue trực tiếp mà không cần begin.

Một chương trình hoàn chỉnh nhỏ: tần suất từ

path = ARGV.fetch(0) { abort "usage: ruby words.rb FILE" }

begin
  text = File.read(path).downcase
rescue Errno::ENOENT
  abort "file not found: #{path}"
end

counts = text.scan(/[a-z']+/).tally
counts.max_by(5) { |_word, n| n }.each do |word, n|
  puts format("%5d  %s", n, word)
end

Chạy bằng ruby words.rb notes.txt. tally đếm các phần tử giống nhau vào một hash, còn max_by(5) trả về năm mục có số đếm cao nhất.

Lỗi thường gặp của người mới

  • Quên end để đóng khối if, def, class hoặc do.
  • Trộn lẫn khóa chuỗi và khóa symbol: h["name"] và h[:name] là hai khóa khác nhau.
  • Dùng dấu nháy đơn mà vẫn mong nội suy #{} hoạt động.
  • Gọi phương thức có ! mà không nhận ra nó đã thay đổi đối tượng gốc.
  • Dùng Ruby hệ thống cũ thay vì phiên bản mới cài bằng trình quản lý phiên bản.

Học tiếp ở đâu

Bắt đầu với trang tài liệu trên ruby-lang.org, gồm phần hướng dẫn nhanh "Ruby in Twenty Minutes", và dùng docs.ruby-lang.org để tra cứu thư viện lõi và thư viện chuẩn. Học Bundler và gem để quản lý thư viện phụ thuộc, RSpec hoặc Minitest để kiểm thử, rồi đến Ruby on Rails nếu bạn muốn xây dựng ứng dụng web.

Câu hỏi thường gặp

Ruby còn được dùng không?

Có. Ruby on Rails vận hành nhiều sản phẩm web lâu đời, gồm GitHub và Shopify, và Ruby phổ biến trong viết script và công cụ cho lập trình viên. Ruby ít được chọn cho dự án mới hơn Python hay JavaScript, nhưng vẫn được phát triển tích cực.

Ruby khác Ruby on Rails thế nào?

Ruby là ngôn ngữ lập trình. Rails là framework web viết bằng Ruby, cung cấp định tuyến, truy cập cơ sở dữ liệu và mẫu trang.

Symbol trong Ruby là gì?

Symbol như :name là một định danh bất biến và duy nhất. Cùng một symbol luôn là cùng một đối tượng, nên rất hiệu quả cho khóa hash và tên tùy chọn.

Người mới nên học Ruby hay Python?

Cả hai đều là ngôn ngữ đầu tiên tốt với cú pháp dễ đọc. Python có phạm vi dùng rộng hơn, nhất là trong khoa học dữ liệu; Ruby rất giàu biểu đạt và mạnh trong phát triển web với Rails.

Tất cả hướng dẫn lập trình