Ruby 语言学习笔记:核心概念与实践
Ruby 是一门优雅、动态、面向对象的脚本语言,以其简洁的语法和强大的元编程能力而闻名。它由日本程序员松本行弘(Yukihiro Matsumoto,昵称 Matz)开发,旨在提高程序员的生产力,让编程变得更愉快。本文将记录我在学习 Ruby 过程中的一些核心概念和实践心得。
Ruby 的哲学
Matz 曾说过:“Ruby 就像人类的自然语言一样,是一种富有表现力的语言。Ruby 旨在让编程变得更简单、更直观,让开发者能够专注于创造,而不是被复杂的语法和工具所困扰。” 这种哲学体现在 Ruby 的设计中,例如:
- “最少惊奇原则” (Principle of Least Surprise): Ruby 的行为应该符合大多数程序员的直觉。
- “程序员的友好” (Programmer’s Best Friend): Ruby 提供了许多便利的工具和语法糖,使得编写代码更加高效和愉悦。
一切皆对象
在 Ruby 中,万事万物都是对象,包括数字、字符串、甚至 nil。这意味着所有的数据类型都可以调用方法。
1# 数字是对象
2puts 5.class # => Integer
3puts 5.to_s # => "5"
4
5# 字符串是对象
6puts "Hello".class # => String
7puts "Hello".length # => 5
8
9# nil 也是对象
10puts nil.class # => NilClass
11# puts nil.some_method # => NoMethodError: undefined method `some_method' for nil:NilClass
面向对象编程
Ruby 是一个纯粹的面向对象语言。
类 (Class): 用于创建对象的蓝图。
1class Dog 2 attr_accessor :name, :breed # attr_accessor 自动生成 getter 和 setter 方法 3 4 def initialize(name, breed) 5 @name = name 6 @breed = breed 7 end 8 9 def bark 10 puts "Woof!" 11 end 12 13 def introduce 14 puts "My name is #{@name} and I'm a #{@breed}." 15 end 16end 17 18my_dog = Dog.new("Buddy", "Golden Retriever") 19my_dog.bark 20my_dog.introduce 21puts my_dog.name # => Buddyinitialize方法是类的构造函数。@前缀的变量是实例变量,属于对象本身。attr_accessor是一个方便的方法,用于生成读取(getter)和写入(setter)实例变量的方法。
继承 (Inheritance): Ruby 使用
<符号表示继承。1class Poodle < Dog 2 def groom 3 puts "Grooming my fancy fur!" 4 end 5 6 def bark 7 puts "Yip yip!" # 方法重写 (Overriding) 8 end 9end 10 11my_poodle = Poodle.new("Fifi", "Poodle") 12my_poodle.bark # => Yip yip! 13my_poodle.introduce # => My name is Fifi and I'm a Poodle. (继承自 Dog 类) 14my_poodle.groom # => Grooming my fancy fur!模块 (Module): 模块在 Ruby 中扮演两种重要角色:
- 命名空间: 用于组织相关的类和方法,避免命名冲突。
- 混入 (Mixins): 通过
include关键字,可以将模块中的方法“混入”到类中,实现代码的复用,类似于其他语言的多重继承(但 Ruby 不支持多重类继承)。
1module Swimmable 2 def swim 3 puts "I can swim!" 4 end 5end 6 7class Duck 8 include Swimmable # 将 Swimmable 模块的方法混入到 Duck 类 9 def quack 10 puts "Quack!" 11 end 12end 13 14class Person 15 include Swimmable 16end 17 18duck = Duck.new 19duck.quack 20duck.swim # => I can swim! 21 22person = Person.new 23person.swim # => I can swim!
代码块和迭代器
Ruby 中大量使用代码块(Blocks)和迭代器(Iterators),这使得处理集合和执行重复性任务非常简洁。
代码块 (Blocks): 传递给方法的一段未定义的方法体,通常用
{}或do...end括起来。1[1, 2, 3].each { |n| puts n * 2 } 2# => 2 3# => 4 4# => 6 5 6[4, 5, 6].each do |n| 7 puts "Number: #{n}" 8end 9# => Number: 4 10# => Number: 5 11# => Number: 6|n|定义了块变量。
迭代器: 许多 Ruby 方法(如
each,map,select,reject)都接受代码块,并为集合中的每个元素执行该代码块。each: 遍历集合,执行块。map(或collect): 遍历集合,执行块,并将块的返回值组成一个新的数组。select(或filter): 遍历集合,执行块,返回块的返回值“真”的元素组成的新数组。reject: 遍历集合,执行块,返回块的返回值“假”的元素组成的新数组。
1numbers = [1, 2, 3, 4, 5] 2 3doubled_numbers = numbers.map { |n| n * 2 } 4puts doubled_numbers.inspect # => [2, 4, 6, 8, 10] 5 6even_numbers = numbers.select { |n| n.even? } 7puts even_numbers.inspect # => [2, 4] 8 9odd_numbers = numbers.reject { |n| n.even? } 10puts odd_numbers.inspect # => [1, 3, 5]
块、Proc 和 Lambda
- 块: 上面提到的
{}或do...end结构。块不能被独立存储或传递,它们必须与一个方法绑定。 - Proc: Ruby 中表示代码块的对象。你可以创建
Proc对象并将其传递给方法,甚至在方法外调用。1my_proc = Proc.new { |name| puts "Hello, #{name}!" } 2my_proc.call("Alice") # => Hello, Alice! 3 4def greet(greeter_proc) 5 greeter_proc.call("Bob") 6end 7greet(my_proc) # => Hello, Bob! - Lambda: Lambda 也是一种
Proc,但比Proc更严格。Lambda 在调用时会检查参数数量,并且return语句只会从 Lambda 自身返回,而不会跳出外部方法。注意:Lambda 的1my_lambda = lambda { |name| puts "Hi, #{name}!"; return "returned from lambda" } 2result = my_lambda.call("Charlie") # => Hi, Charlie! 3puts result # => returned from lambda 4 5def test_lambda_return(&block) 6 puts "Before calling lambda" 7 yield # 或者 block.call 8 puts "After calling lambda" 9end 10 11test_lambda_return(&my_lambda) 12# => Before calling lambda 13# => Hi, Charlie! 14# => returned from lambda 15# => After calling lambdareturn不会跳出test_lambda_return方法。
元编程 (Metaprogramming)
元编程是指编写能够生成或操作其他代码的代码。Ruby 提供了强大的元编程能力。
动态方法定义:
1class MyClass 2 def method_missing(method_name, *args, &block) 3 puts "You called an undefined method: #{method_name} with args #{args}" 4 # 可以根据 method_name 动态定义方法 5 if method_name == :dynamic_method 6 define_singleton_method(:dynamic_method) do |*dyn_args| 7 puts "This is a dynamically created method with args: #{dyn_args}" 8 end 9 send(:dynamic_method, *args, &block) # 调用新定义的方法 10 else 11 super # 如果不是预期的动态方法,则调用父类的 method_missing 12 end 13 end 14end 15 16obj = MyClass.new 17obj.some_undefined_method(1, 2) # => You called an undefined method: some_undefined_method with args [1, 2] 18obj.dynamic_method(3, 4) # => You called an undefined method: dynamic_method with args [3, 4] 19 # => This is a dynamically created method with args: [3, 4]method_missing是一个特殊方法,当调用一个类或对象上不存在的方法时会被调用。define_singleton_method可以在运行时为对象定义方法。
Open Classes: Ruby 允许你