当前位置: 首页 > article >正文

【KWDB 创作者计划】_ruby基础语法

以下是 Ruby 基础语法的简明总结,适合快速入门:


一、变量与常量

1. 局部变量

小写字母或下划线开头,作用域为当前代码块。

name = "Alice"
_age = 20

//局部变量附加:{{{{

声明与命名规则

  1. 命名格式

    • 以小写字母或下划线 _ 开头,如 name_count
    • 后续字符可包含字母、数字和下划线。
    • 避免与 Ruby 关键字(如 classdef)冲突。
  2. 声明方式

    • 通过赋值 = 隐式声明,无需显式类型。
    age = 25           # 声明局部变量 age
    _message = "Hello" # 声明局部变量 _message
    

作用域规则

  1. 代码块内外的可见性

    • 块参数会遮蔽外部变量

      x = 10
      3.times do |x|    # 块参数 x 遮蔽外部变量puts x          # 输出 0, 1, 2
      end
      puts x            # 输出 10(外部变量未被修改)
      
    • 无块参数时可访问外部变量

      x = 5
      3.times dox = 10         # 修改外部变量 x
      end
      puts x            # 输出 10
      
  2. 方法内的局部变量

    • 方法内部变量对外不可见:

      def test_methodlocal_var = "内部变量"
      end
      test_method
      puts local_var    # NameError: undefined local variable
      
    • 方法无法访问定义它的外部局部变量:

      outer_var = "外部变量"
      def show_varputs outer_var  # NameError: undefined local variable
      end
      show_var
      
  3. 条件与循环中的变量

    • 即使条件未执行,变量也会被声明(初始化为 nil):

      if falsea = 1          # 代码未执行,但变量 a 已声明
      end
      puts a            # 输出 nil
      
    • 循环(如 while)不创建新作用域:

      i = 0
      while i < 3inner = ii += 1
      end
      puts inner        # 输出 2
      

变量遮蔽与覆盖

  1. 内部作用域遮蔽外部变量

    x = 100
    1.times dox = 200          # 直接修改外部变量 xy = 300          # 声明新变量 y(作用域在块内)
    end
    puts x             # 输出 200
    puts y             # NameError: undefined local variable
    
  2. 方法参数与局部变量同名

    def demo(x)x = 20           # 修改的是参数 x,不影响外部变量puts x           # 输出 20
    end
    x = 10
    demo(x)
    puts x             # 输出 10
    

特殊场景

  1. 顶层作用域的局部变量

    • 在文件或交互式环境(如 irb)顶层定义的局部变量,作用域为当前文件或会话:
      top_var = "顶层变量"
      def show_top_varputs top_var   # NameError: undefined local variable
      end
      show_top_var
      
  2. 类/模块定义中的局部变量

    • 在类或模块定义中声明的局部变量,仅在该定义范围内有效:
      class MyClassclass_var = "类定义内的局部变量"def self.show_varputs class_var # NameError: undefined local variableend
      end
      

最佳实践

  1. 避免变量遮蔽:谨慎使用与外部作用域同名的变量。
  2. 限制作用域:在最小必要范围内定义变量,减少副作用。
  3. 明确命名:使用有意义的变量名(如 user_count 而非 uc)。

总结

场景行为
块内无参数赋值可读写外部变量
块带同名参数遮蔽外部变量,内部操作不影响外部
方法内部变量仅在方法内有效,外部不可见
条件/循环中的变量即使代码未执行,变量也会被声明(值为 nil
类定义中的变量仅在类定义过程中有效,类方法无法访问

理解局部变量的作用域规则是编写可维护 Ruby 代码的基础,尤其在处理复杂逻辑时能避免意外的变量污染或覆盖。

//局部变量附加结束}}}}

2. 实例变量

@ 开头,属于对象实例。

@name = "Bob"

//实例变量附加:{{{{
实例变量(Instance Variables)是面向对象编程的核心概念,用于存储对象的状态。以下是其详细规则和使用方法:

定义与基本特性

  1. 命名规则

    • @ 符号开头,如 @name@age
    • 后续字符可包含字母、数字和下划线。
    • 默认值为 nil(未显式赋值时)。
  2. 作用域

    • 属于对象实例:每个对象的实例变量独立存在。
    • 在类的方法中可访问:在类的任何实例方法中均可读写。

声明与访问

  1. 直接赋值
class Persondef initialize(name)@name = name  # 在 initialize 方法中初始化enddef greet"Hello, #{@name}!"  # 在方法中访问end
endperson = Person.new("Alice")
puts person.greet  # => "Hello, Alice!"

//class Person代码的解释开始:
这段 Ruby 脚本定义了一个 Person 类,并演示了如何创建对象实例和调用方法。以下是逐行解释:

  1. 定义 Person
class Person# 类体开始
end
  • class Person:定义一个名为 Person 的类。
  • Ruby 的类名需以 大写字母开头,采用驼峰式命名。
  1. 构造方法 initialize
def initialize(name)@name = name  # 初始化实例变量 @name
end
  • initialize:类的构造方法,在调用 Person.new 时自动执行。
  • name:构造方法的参数,用于接收外部传入的值。
  • @name = name:将参数 name 赋值给实例变量 @name
    • @name:以 @ 开头的变量是实例变量,属于对象实例的私有状态。
  1. 实例方法 greet
def greet"Hello, #{@name}!"  # 使用实例变量 @name 拼接字符串
end
  • greet:定义一个名为 greet 的实例方法。
  • #{@name}:字符串插值语法,将 @name 的值嵌入字符串中。
  • 方法返回值为字符串(Ruby 中方法的最后一行的值会被自动返回)。
  1. 创建对象实例
person = Person.new("Alice")
  • Person.new("Alice"):调用 Person 类的 new 方法创建实例。
    • new 方法会触发 initialize 方法,并将 "Alice" 作为参数传递。
    • 此时 @name 被赋值为 "Alice"
  • person:变量指向新创建的 Person 实例对象。
  1. 调用方法并输出结果
puts person.greet  # => "Hello, Alice!"
  • person.greet:调用 person 实例的 greet 方法。
    • 方法返回字符串 "Hello, Alice!"
  • puts:输出字符串到控制台。

//class Person代码的解释结束

  1. 通过访问器方法
    Ruby 提供快捷方法生成 gettersetter
  • attr_reader:生成 getter 方法。
  • attr_writer:生成 setter 方法。
  • attr_accessor:生成 getter 和 setter。
class Userattr_accessor :email  # 自动生成 @email 的读写方法attr_reader :id       # 只生成 @id 的读方法def initialize(id)@id = idend
enduser = User.new(1)
user.email = "alice@example.com"
puts user.email  # => "alice@example.com"

//访问器方法代码解释 开始
属性访问器(Attribute Accessors),属性访问器(Attribute Accessors)是一种元编程机制,用于快速生成实例变量的 getter(读方法)和 setter(写方法)。Ruby 提供了三个核心方法简化操作:
三种属性访问器

  1. attr_reader
    生成 只读方法(getter),允许外部读取实例变量。

    class Userattr_reader :id  # 生成 def id; @id; enddef initialize(id)@id = idend
    enduser = User.new(1)
    puts user.id   # => 1
    user.id = 2    # NoMethodError(无写方法)
    
  2. attr_writer
    生成 只写方法(setter),允许外部修改实例变量。

    class Userattr_writer :email  # 生成 def email=(value); @email = value; enddef initialize(email)@email = emailend
    enduser = User.new("alice@example.com")
    user.email = "bob@example.com"  # 修改成功
    puts user.email                 # NoMethodError(无读方法)
    
  3. attr_accessor
    生成 读写方法(getter + setter),最常用。

    class Productattr_accessor :price  # 生成读方法和写方法def initialize(price)@price = priceend
    endproduct = Product.new(100)
    product.price = 150
    puts product.price  # => 150
    

访问器的底层原理

  1. 手动实现等效代码

    class User# attr_reader :name 的等效代码def name@nameend# attr_writer :name 的等效代码def name=(value)@name = valueend
    end
    
  2. 动态生成方法
    attr_* 方法本质是通过元编程动态定义方法:

    class Classdef my_attr_reader(name)define_method(name) doinstance_variable_get("@#{name}")endend
    end
    

高级用法与技巧

  1. 批量定义访问器

    class Personattr_accessor :name, :age, :gender  # 多个属性
    end
    
  2. 添加自定义逻辑

    class Temperatureattr_reader :celsiusdef celsius=(value)raise "温度不能低于绝对零度" if value < -273.15@celsius = valueend
    endtemp = Temperature.new
    temp.celsius = -300  # RuntimeError
    
  3. 结合初始化方法

    class Bookattr_accessor :title, :authordef initialize(title, author)@title = title@author = authorend
    endbook = Book.new("Ruby指南", "松本行弘")
    book.title = "Ruby高级编程"
    
  4. 继承行为
    父类的访问器方法会被子类继承:

    class Admin < User
    end
    admin = Admin.new(1)
    admin.email = "admin@example.com"  # 正常执行(继承 attr_accessor)
    

//访问器方法代码解释 结束

实例变量的特性

  1. 封装性
  • 实例变量默认是 私有 的,外部无法直接访问。
  • 必须通过方法暴露(如 attr_accessor)。
  1. 动态增删
    可在运行时动态添加或删除实例变量:
obj = Object.new
obj.instance_variable_set(:@x, 10)  # 动态添加 @x
puts obj.instance_variable_get(:@x) # => 10
obj.remove_instance_variable(:@x)   # 删除 @x

//动态增删附加 开始:
这段 Ruby 脚本演示了如何通过反射机制 动态管理实例变量
代码逐行解析

  1. 创建新对象
obj = Object.new
  • 作用:创建一个 Object 类的匿名实例。
  • 对象状态:此时 obj 没有任何预定义的实例变量。
  1. 动态添加实例变量 @x
obj.instance_variable_set(:@x, 10)
  • instance_variable_set 方法
    • 功能:直接为对象设置实例变量。
    • 参数
      • 第一个参数:符号形式的变量名(必须包含 @,如 :@x)。
      • 第二个参数:变量值(可以是任意对象)。
    • 结果:对象 obj 新增实例变量 @x,值为 10
  1. 读取实例变量 @x 的值
puts obj.instance_variable_get(:@x) # => 10
  • instance_variable_get 方法
    • 功能:直接读取对象的实例变量值。
    • 参数:符号形式的变量名(如 :@x)。
    • 返回值:变量的当前值,若变量不存在则返回 nil
  1. 删除实例变量 @x
obj.remove_instance_variable(:@x)
  • remove_instance_variable 方法
    • 功能:从对象中删除指定的实例变量。
    • 参数:符号形式的变量名(如 :@x)。
    • 返回值:被删除变量的值。
    • 注意:若变量不存在会抛出 NameError

关键方法和注意事项

方法名用途注意事项
instance_variable_set动态设置实例变量变量名必须@ 开头,否则抛出 NameError
instance_variable_get动态读取实例变量变量不存在时返回 nil,不会报错
remove_instance_variable动态删除实例变量变量不存在时抛出 NameError,需确保变量存在或使用 begin rescue 处理

使用场景

  1. 动态对象构造
    在运行时根据条件动态添加属性:

    data = { name: "Alice", age: 20 }
    obj = Object.new
    data.each { |key, value| obj.instance_variable_set("@#{key}", value) }
    
  2. 元编程和框架开发
    在编写灵活的程序结构时(如 ORM、序列化工具):

    class Serializerdef serialize(obj)obj.instance_variables.each_with_object({}) do |var, hash|hash[var] = obj.instance_variable_get(var)endend
    end
    
  3. 调试和探索性编程
    快速查看或修改对象内部状态:

    user = User.find(1)
    user.instance_variable_set(:@password, "hacked") # 危险操作!仅用于演示
    obj = Object.new
    obj.instance_variable_set(:@不存在的方法, 100) # 合法但可能导致后续逻辑混乱# 使用下判断
    if obj.instance_variable_defined?(:@x)obj.remove_instance_variable(:@x)
    end
    

// 动态增删附加 结束

  1. 与类变量的对比
实例变量 (@var)类变量 (@@var)
作用域对象实例内类及其所有实例共享
继承行为子类对象不继承父类实例变量子类共享父类的类变量

高级用法
5. 元编程访问

class Dogdef initialize(name)@name = nameend
enddog = Dog.new("Buddy")# 获取所有实例变量名
dog.instance_variables  # => [:@name]# 检查是否存在实例变量
dog.instance_variable_defined?(:@name)  # => true
  1. 在模块中定义实例变量
module Loggabledef log(message)@logs ||= []  # 若 @logs 不存在则初始化为空数组@logs << messageend
endclass Serviceinclude Loggable
endservice = Service.new
service.log("Event 1")
service.instance_variable_get(:@logs)  # => ["Event 1"]

注意事项

  1. 避免未初始化访问
    实例变量未赋值时为 nil,需注意空值问题:

    class Productdef print_price"Price: #{@price}"  # @price 未初始化时为 nilend
    endProduct.new.print_price  # => "Price: "
    
  2. 命名冲突
    子类可能意外覆盖父类的实例变量:

    class Animaldef initialize@name = "Animal"end
    endclass Cat < Animaldef initialize@name = "Cat"  # 覆盖父类的 @nameend
    end
    

总结

场景实例变量的行为
对象初始化通过 initialize 方法赋值
方法间共享同一对象的实例方法均可访问
动态管理支持运行时增删
封装性必须通过方法暴露给外部

实例变量是 Ruby 面向对象的核心机制,合理使用它们可以高效管理对象状态!

//实例变量附加结束}}}}

3. 类变量

@@ 开头,属于整个类。

@@count = 0

// 类变量 附加开始{{{{
在 Ruby 中,类变量(Class Variables)是一种特殊类型的变量,用于在类层级共享数据。

定义与基本特性

  1. 命名规则

    • @@ 开头,如 @@count@@config
    • 后续字符遵循变量命名规范(字母、数字、下划线)。
    • 必须显式初始化(否则抛出 NameError)。
  2. 作用域

    • 类层级共享:类变量属于类本身,被所有实例和子类共享。
    • 全局可见:在类定义、实例方法、类方法中均可访问。

基本用法示例

1. 类变量初始化与访问
class Counter@@count = 0  # 初始化类变量def self.increment@@count += 1enddef self.total@@countend
endCounter.increment
Counter.increment
puts Counter.total  # => 2
  1. 实例方法访问类变量
class User@@users = []def initialize(name)@name = name@@users << self  # 将实例自身加入类变量数组enddef self.all_users@@usersend
endalice = User.new("Alice")
bob = User.new("Bob")
puts User.all_users.size  # => 2

类变量的继承行为

  1. 子类共享父类的类变量
class Parent@@value = 100def self.value@@valueend
endclass Child < Parentdef self.change_value@@value = 200end
endChild.change_value
puts Parent.value  # => 200(父类的类变量被子类修改)
  1. 所有子类共享同一变量
class A@@list = []
endclass B < A; end
class C < A; endB.class_variable_get(:@@list) << "item"
puts C.class_variable_get(:@@list)  # => ["item"]

类变量的替代方案:类实例变量
由于类变量的共享特性容易导致意外修改,Ruby 开发者常使用 类实例变量 作为替代:

  1. 类实例变量特性
  • @ 开头,属于类对象(而非类本身)。
  • 不被子类继承,每个类独立拥有自己的副本。
  • 通过类方法中的 attr_accessor 定义。
  1. 示例对比
class Parent@count = 0  # 类实例变量class << selfattr_accessor :count  # 定义类实例变量的访问器end
endclass Child < Parent; endParent.count = 5
Child.count = 10
puts Parent.count  # => 5(不受子类影响)
puts Child.count   # => 10

类变量使用场景

场景示例
全局类级计数器统计实例数量、方法调用次数
共享配置数据库连接、日志级别设置
缓存数据存储类级别的计算结果或临时数据

注意事项与陷阱

  1. 初始化位置
    类变量必须在类或模块内部初始化(不能在其他作用域)。

    class Demo@@value = 0  # 正确:在类体内初始化
    end# @@value = 0  # 错误:顶层作用域无法初始化类变量
    
  2. 线程安全问题
    类变量在多线程环境中可能引发竞态条件,需加锁保护:

    class Counter@@mutex = Mutex.new@@count = 0def self.safe_increment@@mutex.synchronize { @@count += 1 }end
    end
    
  3. 避免过度共享
    类变量的全局性容易导致代码耦合,应谨慎使用。

总结对比

特性类变量 (@@var)类实例变量 (@var)
作用域类及其所有子类共享仅在定义它的类中有效
继承行为子类修改影响父类和其他子类不继承,每个类独立
初始化位置必须在类或模块内部可在类方法或类体内初始化
适用场景需要跨继承树共享数据需要类级别的私有状态

//类变量 附加结束}}}}

4. 全局变量

$ 开头,作用域全局。

$debug_mode = true

//全局变量附件开始
全局变量(Global Variables)是作用域覆盖整个程序(包括所有模块、类和方法的变量)。

全局变量的核心规则

  1. 命名规则

    • $ 开头,如 $counter$logger
    • 后续字符遵循变量命名规范(字母、数字、下划线)。
  2. 作用域

    • 全局可见:在程序的任何位置(包括类、模块、方法、块)均可读写。
  3. 默认值

    • 未初始化的全局变量值为 nil

基本用法示例

  1. 声明与赋值
$app_name = "MyApp"  # 定义全局变量class Userdef print_app_nameputs $app_name  # 在类内访问全局变量end
enddef log_message$app_name = "NewApp"  # 在方法内修改全局变量
endlog_message
User.new.print_app_name  # 输出 "NewApp"
  1. 预定义全局变量
    Ruby 有一些内置的全局变量(如 $!$@),用于访问系统信息或异常上下文:
begin1 / 0
rescue => eputs $!  # 输出最后抛出的异常信息(等同 e.message)puts $@  # 输出异常堆栈跟踪(等同 e.backtrace)
end

全局变量的优缺点
优点

  • 快速共享数据:无需通过参数传递,直接跨作用域访问。
  • 临时调试工具:快速记录程序状态。

缺点

  • 破坏封装性:导致代码耦合,难以追踪修改来源。
  • 命名冲突风险:全局变量名可能被意外覆盖。
  • 维护困难:大型项目中难以管理。

使用场景(谨慎选择!)

场景示例
跨模块共享配置日志级别、环境变量
临时调试或性能监控记录方法调用次数
单例模式简单实现全局唯一的数据库连接对象

替代方案(推荐优先使用)

  1. 常量(全大写命名)

    module ConfigAPP_NAME = "MyApp"  # 常量,可被修改但会警告
    endputs Config::APP_NAME
    
  2. 类/模块变量

    class AppState@@instance_count = 0  # 类变量def self.increment@@instance_count += 1end
    end
    
  3. 单例模式

    require 'singleton'class Loggerinclude Singletonattr_accessor :leveldef initialize@level = "INFO"end
    endLogger.instance.level = "DEBUG"
    

注意事项

  1. 避免滥用:仅在无其他替代方案时使用。

  2. 命名规范:使用明确的前缀(如 $myapp_logger),避免与内置全局变量冲突。

  3. 线程安全:多线程环境中需加锁保护。

    $counter = 0
    $counter_mutex = Mutex.newdef increment_counter$counter_mutex.synchronize { $counter += 1 }
    end
    
  4. 重置全局变量:可通过赋值 nil 释放资源。

    $db_connection = nil  # 断开数据库连接并释放内存
    

内置全局变量

变量用途
$!最后抛出的异常对象
$@最后异常的堆栈跟踪信息
$?最后执行的子进程状态
$0当前执行的脚本文件名
$:Ruby 的加载路径(等同 $LOAD_PATH
$_最后读取的输入行(如 gets 结果)

最佳实践:除非必要,优先使用常量、类变量或依赖注入模式替代全局变量。
//全局变量附件结束

5. 常量

全大写字母,约定不可修改(修改会警告)。

PI = 3.14159

//常量附加开始
常量(Constants)是一种用于存储固定值的标识符,其命名以大写字母开头,通常用于定义配置、枚举值或全局共享数据。

常量的基本规则

  1. 命名规范

    • 必须以大写字母开头(如 PIMAX_SIZE)。
    • 约定全大写加下划线(如 DEFAULT_TIMEOUT),但也可用驼峰式(如 AppConfig)。
  2. 赋值与修改

    • 应保持不可变:Ruby 允许修改常量,但会发出警告。
    • 重新赋值触发警告:
      PI = 3.14
      PI = 3.14159  # 输出 warning: already initialized constant PI
      
  3. 作用域

    • 定义在类、模块或顶层作用域。
    • 通过命名空间访问(如 MyClass::CONST)。

常量的定义与访问

  1. 顶层常量(全局可见)
APP_NAME = "MyApp"  # 顶层常量class Userdef show_app_nameAPP_NAME  # 直接访问end
endputs APP_NAME  # => "MyApp"
  1. 类/模块内的常量
class MathUtilsPI = 3.14159  # 类常量def circle_area(radius)PI * radius ** 2end
endputs MathUtils::PI  # => 3.14159
  1. 模块中的常量
module ColorsRED = "#FF0000"
endclass Carinclude Colors
endputs Car::RED  # => "#FF0000"(通过 include 引入)

常量的查找规则

  1. 继承链查找
    子类会继承父类的常量,但可覆盖:
class ParentVALUE = 100
endclass Child < ParentVALUE = 200  # 覆盖父类常量
endputs Parent::VALUE  # => 100
puts Child::VALUE    # => 200
  1. 作用域解析运算符 ::
module OuterCONST = "Outer"module InnerCONST = "Inner"def self.showputs CONST         # => "Inner"puts Outer::CONST  # => "Outer"endend
endOuter::Inner.show

常量 vs 类变量

特性常量 (CONST)类变量 (@@var)
命名规则大写字母开头@@ 开头
可修改性可修改(有警告)可随意修改
作用域类/模块或全局类及其子类共享
继承行为子类可覆盖子类共享同一变量

最佳实践

  1. 避免修改常量
    如需可变配置,改用类方法或单例模式:

    class Configdef self.timeout@timeout ||= 10  # 可修改且无警告end
    end
    
  2. 冻结常量(不可变对象)
    防止常量引用的对象被修改:

    COLORS = { red: "#FF0000" }.freeze
    COLORS[:red] = "#FF1234"  # RuntimeError: can't modify frozen Hash
    
  3. 使用模块组织常量

    module SettingsTIMEOUT = 30API_KEY = "secret"
    endputs Settings::API_KEY
    

动态操作常量

  1. 动态定义与访问
class Dynamicconst_set(:MAX, 100)         # 定义常量 MAXputs const_get(:MAX)         # => 100puts constants.include?(:MAX) # => true
end
  1. 检查常量存在性
if MyClass.const_defined?(:VERSION)puts MyClass::VERSION
end

常见错误

  1. 未初始化的常量

    puts UNDEFINED_CONST  # NameError: uninitialized constant UNDEFINED_CONST
    
  2. 命名空间遗漏

    module Amodule BCONST = 1end
    end
    puts B::CONST  # NameError: uninitialized constant B(需写 A::B::CONST)
    

//常量附加结束


二、数据类型

1. 数值(Numberic)

以下是 Ruby 中 数值类型(Numeric) 的详细解析,涵盖整数、浮点数、数值运算、类型转换以及实用技巧。

数值类型分类
Ruby 的数值类型分为 整数浮点数,所有数值均为对象,属于 Numeric 类的子类。

类型类名说明示例
整数Integer包括小整数(Fixnum)和大整数(Bignum),Ruby 自动处理类型转换42, 12345678901234567890
浮点数Float双精度浮点数,遵循 IEEE 754 标准3.14, 6.022e23
有理数Rational精确分数(需手动创建或引入库)Rational(3, 4) => 3/4
复数Complex复数类型(需手动创建或引入库)Complex(2, 3) => 2+3i

整数(Integer)

  1. 表示方式
  • 十进制:默认写法,如 123
  • 二进制:以 0b0B 开头,如 0b1010(十进制的 10)。
  • 八进制:以 00o 开头,如 0o755(十进制的 493)。
  • 十六进制:以 0x 开头,如 0xFF(十进制的 255)。
  1. 自动大整数支持
    Ruby 自动处理整数溢出,小整数(Fixnum)和大整数(Bignum)无缝切换:
a = 123           # => 123(Fixnum)
b = 1234567890 * 9876543210  # => 12193263113702179500(Bignum)
  1. 常用方法
方法说明示例
times { |i| }循环指定次数3.times { |i| puts i } 输出 0,1,2
even?, odd?判断奇偶4.even? => true
to_s(base)转换为字符串(指定进制)255.to_s(16) => "ff"
abs绝对值-5.abs => 5

浮点数(Float)
5. 表示方式

  • 常规写法:3.14, -0.001
  • 科学计数法:6.022e23(6.022 × 10²³)。
  1. 精度问题与解决方案
    浮点数计算可能因精度丢失导致误差:
0.1 + 0.2  # => 0.30000000000000004(并非精确的 0.3)

解决方案

  • 使用 Rational 类型
    (Rational(1, 10) + Rational(2, 10)).to_f  # => 0.3
    
  • BigDecimal(高精度计算):
    require 'bigdecimal'
    a = BigDecimal("0.1")
    b = BigDecimal("0.2")
    a + b  # => 0.3e0
    

数值运算

  1. 基本运算符
运算符说明示例
+加法5 + 3 => 8
-减法5 - 3 => 2
*乘法5 * 3 => 15
/除法5 / 2 => 2(整数除法)
5.to_f / 2 => 2.5
%取模5 % 2 => 1
**幂运算2 ** 3 => 8
  1. 除法行为
  • 整数除法:结果自动向下取整。
    7 / 3    # => 2
    
  • 浮点除法:强制转换为浮点数。
    7.to_f / 3  # => 2.333...
    7 / 3.0     # => 2.333...
    
  1. 链式比较
    Ruby 支持数学中的链式比较:
1 < 2 < 3     # => true
5 <= x <= 10  # 判断 x 是否在 5 到 10 之间

类型转换

目标类型方法示例
整数转浮点to_f5.to_f => 5.0
浮点转整数to_i(截断)3.9.to_i => 3
四舍五入round3.6.round => 4
向上取整ceil3.2.ceil => 4
向下取整floor3.9.floor => 3
字符串转数值to_i, to_f"42".to_i => 42

实用技巧

  1. 随机数生成
rand(10)        # 生成 0~9 的随机整数
rand(5.0..10.0) # 生成 5.0 到 10.0 的随机浮点数
  1. 数值格式化
sprintf("%.2f", 3.1415)  # => "3.14"
3.1415.round(2)          # => 3.14(四舍五入保留两位小数)
  1. 数值范围检查
(1..100).cover?(50)  # => true(检查数值是否在范围内)
  1. 字符串(String)
    单引号(不转义)或双引号(支持转义和插值)。

    str1 = 'Hello \n World'  # 输出换行符
    str2 = "Hello #{name}"   # 插值:Hello Alice
    
  2. 符号(Symbol)
    轻量级字符串,以 : 开头,常用于哈希键。

    :user_id
    
  3. 数组(Array)
    有序集合,通过索引访问。

    nums = [1, 2, 3]
    nums[0]  # => 1
    
  4. 哈希(Hash)
    键值对集合,键可以是任意对象。

    person = { name: "Alice", age: 20 }
    person[:name]  # => "Alice"
    
  5. 范围(Range)
    表示连续区间,常用于迭代。

    (1..5).each { |n| puts n }  # 1到5
    (1...5).each { |n| puts n } # 1到4
    

三、运算符

  1. 算术运算符
    +, -, *, /, %, **(幂运算)。

    2 ** 3  # => 8
    10 % 3  # => 1
    
  2. 比较运算符
    ==, !=, >, <, >=, <=, <=>(返回 -1, 0, 1)。

    5 <=> 3  # => 1(5 > 3)
    
  3. 逻辑运算符
    &&, ||, !(也可用 and, or, not,但优先级不同)。

    true && false  # => false
    
  4. 赋值运算符
    =, +=, -=, *=, /=, %=

    x = 5
    x += 3  # => 8
    

四、控制结构

  1. 条件判断

    # if/elsif/else
    if age >= 18puts "Adult"
    elsif age > 0puts "Child"
    elseputs "Invalid"
    end# 三元运算符
    result = (score > 60) ? "Pass" : "Fail"
    
  2. 循环

    # while 循环
    i = 0
    while i < 3puts ii += 1
    end# until 循环
    until i >= 3puts ii += 1
    end# for 循环(较少使用)
    for num in [1, 2, 3]puts num
    end
    
  3. 迭代器

    # each 方法
    (1..3).each { |n| puts n }# map 方法
    doubled = [1, 2, 3].map { |n| n * 2 }  # => [2, 4, 6]
    

五、方法定义

  1. 基本语法

    def greet(name)"Hello, #{name}!"
    end
    greet("Ruby")  # => "Hello, Ruby!"
    
  2. 默认参数

    def add(a, b = 1)a + b
    end
    add(3)    # => 4
    add(3, 5) # => 8
    
  3. 可变参数

    def sum(*nums)nums.sum
    end
    sum(1, 2, 3)  # => 6
    

六、异常处理

begin# 可能出错的代码result = 10 / 0
rescue ZeroDivisionError => eputs "Error: #{e.message}"
ensureputs "Cleanup code here"
end

七、注释

  1. 单行注释

    # 这是一个注释
    
  2. 多行注释

    =begin
    这是一个多行注释
    可以写多行内容
    =end
    

八、特殊语法

  1. % 符号快捷语法

    %w[apple banana cherry]  # => ["apple", "banana", "cherry"](字符串数组)
    %i[red green blue]       # => [:red, :green, :blue](符号数组)
    
  2. 并行赋值

    a, b = 1, 2  # a=1, b=2
    a, b = b, a   # 交换值:a=2, b=1
    

九、代码块(Block)

  1. 使用 {}do...end

    # 单行用 {}
    [1, 2, 3].each { |n| puts n }# 多行用 do...end
    [1, 2, 3].each do |n|puts "Number: #{n}"
    end
    
  2. 自定义接受块的方法

    def repeat(times)times.times { yield }  # yield 调用块
    endrepeat(3) { puts "Hello!" }  # 输出 3 次 Hello
    

十、常用方法示例

  1. 字符串操作

    "ruby".upcase      # => "RUBY"
    "HELLO".downcase   # => "hello"
    "  test  ".strip   # => "test"
    
  2. 数组操作

    [1, 2, 3].include?(2)  # => true
    [1, 2, 3].push(4)      # => [1, 2, 3, 4]
    [1, 2, 3].join("-")    # => "1-2-3"
    

十一、ruby保留关键词

以下是 Ruby 的 全部关键字列表(基于 Ruby 3.x 版本),这些单词具有特殊语法含义,不可用作变量名或方法名:

控制流

关键字说明
if条件判断
else条件分支
elsif多条件分支
unless反向条件判断
case多条件匹配
whencase 语句的分支条件
then简化条件语法
end结束代码块

循环与迭代

关键字说明
while条件循环
until反向条件循环
for遍历循环(较少使用)
in用于 forcase
do定义循环/块的开始
break跳出循环
next跳过当前迭代
redo重新执行当前迭代
retry重新开始循环(已废弃)

类与模块

关键字说明
class定义类
module定义模块
def定义方法
undef取消方法定义
alias方法别名
super调用父类方法
self当前对象

异常处理

关键字说明
begin异常处理块开始
rescue捕获异常
ensure确保执行(类似 finally)
raise抛出异常
throw抛出符号(与 catch 配合)
catch捕获符号

访问控制

关键字说明
public公开方法
private私有方法
protected受保护方法

逻辑与运算符

关键字说明
and逻辑与(低优先级)
or逻辑或(低优先级)
not逻辑非
true布尔真值
false布尔假值
nil空值

其他核心关键字

关键字说明
return从方法返回值
yield调用块
__FILE__当前文件名(伪变量)
__LINE__当前行号(伪变量)
BEGIN程序启动前执行的代码块
END程序退出前执行的代码块
defined?检查标识符是否已定义

模式匹配(Ruby 2.7+)

关键字说明
in模式匹配分支

注意

  1. 非关键字但需谨慎使用
    putsgets 等是全局方法,而非关键字。
    proclambda 是类或方法,可被覆盖(但强烈建议不要这样做)。

  2. 版本差异
    retry 在循环中已废弃(但仍可用于 begin/rescue 块)。
    in 在 Ruby 2.7+ 中用于模式匹配。


完整列表(按字母排序):
__FILE__, __LINE__, BEGIN, END, alias, and, begin, break, case, catch, class, def, defined?, do, else, elsif, end, ensure, false, for, if, in, module, next, nil, not, or, redo, rescue, retry, return, self, super, then, true, undef, unless, until, when, while, yield


总结

Ruby 语法以简洁灵活著称,核心特点是:

  • 无分号,代码块通过缩进或 end 结束。
  • 动态类型,无需声明变量类型。
  • 一切皆对象,方法调用可链式操作。

建议通过实际编码练习巩固语法,例如尝试编写小型脚本或使用 Ruby Playground 在线工具。

— END —

相关文章:

【KWDB 创作者计划】_ruby基础语法

以下是 Ruby 基础语法的简明总结&#xff0c;适合快速入门&#xff1a; 一、变量与常量 1. 局部变量 小写字母或下划线开头&#xff0c;作用域为当前代码块。 name "Alice" _age 20//局部变量附加&#xff1a;{{{{ 声明与命名规则 命名格式 以小写字母或下划线…...

Python Cookbook-5.15 根据姓的首字母将人名排序和分组

任务 想将一组人名写入一个地址簿&#xff0c;同时还希望地址簿能够根据姓的首字母进行分组&#xff0c;且按照字母顺序表排序。 解决方案 Python 2.4 的新 itertools.groupby 函数使得这个任务很简单: import itertools def qroupnames(name_iterable):sorted_names sort…...

2025 蓝桥杯省赛c++B组个人题解

声明 本题解为退役蒻苟所写&#xff0c;不保证正确性&#xff0c;仅供参考。 花了大概2个半小时写完&#xff0c;感觉比去年省赛简单&#xff0c;难度大概等价于 codeforces dv4.5 吧 菜鸡不熟悉树上背包&#xff0c;调了一个多小时 题目旁边的是 cf 预测分 所有代码均以通…...

Centos7.9 升级内核,安装RTX5880驱动

系统镜像下载 https://vault.centos.org/7.9.2009/isos/x86_64/CentOS-7-x86_64-DVD-2009.iso 系统安装步骤省略 开始安装显卡驱动 远程登录查看内核 [root192 ~]# uname -a Linux 192.168.119.166 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x8…...

Xdocreport实现根据模板导出word

只使用freemaker生成简单的word文档很容易&#xff0c;但是当word文档需要插入动态图片&#xff0c;带循环数据&#xff0c;且含有富文本时解决起来相对比较复杂&#xff0c;但是使用Xdocreport可以轻易解决。 Xdocreport既可以实现文档填充也可以实现文档转换&#xff0c;此处…...

运行一次性任务与定时任务

运行一次性任务与定时任务 文章目录 运行一次性任务与定时任务[toc]一、使用Job运行一次性任务1.创建一次性任务2.测试一次性任务3.删除Job 二、使用CronJob运行定时任务1.创建定时任务2.测试定时任务3.删除CronJob 一、使用Job运行一次性任务 1.创建一次性任务 &#xff08;…...

解决VS2022中scanf报错C4996

这个的原因是因为新版的VS认为scanf不安全&#xff0c;要去使用scanf_s&#xff0c;但在C语言中就需要scanf&#xff0c;所以我们只要以以下步骤解决就可以了。 只要加入宏定义即可 #define _CRT_SECURE_NO_WARNINGS 因为本人已经很少写小案例了&#xff0c;所以就用这个办法…...

当当平台商品详情接口设计与调用指南

当当平台商品详情接口设计与调用指南 接口名称 GET /api/product/detail 图书商品核心信息查询接口 请求参数说明 参数名称 类型 是否必填 说明 isbn string 是 国际标准书号(支持13位/10位) product_id string 否 平台内部商品编号&#xff08;与…...

sql server分析表大小

使用自动存储过程查询 EXEC sp_spaceused YourTableName; rows&#xff1a;表中的行数。reserved&#xff1a;表占用的总空间&#xff08;包括数据和索引&#xff09;。data&#xff1a;表数据占用的空间。index_size&#xff1a;索引占用的空间。unused&#xff1a;未使用的空…...

《AI大模型应知应会100篇》第13篇:大模型评测标准:如何判断一个模型的优劣

第13篇&#xff1a;大模型评测标准&#xff1a;如何判断一个模型的优劣 摘要 近年来&#xff0c;大语言模型&#xff08;LLMs&#xff09;在自然语言处理、代码生成、多模态任务等领域取得了显著进展。然而&#xff0c;随着模型数量和规模的增长&#xff0c;如何科学评估这些模…...

Linux基础9

一、日志管理 > 日志配置文件&#xff1a; > > ​ /var/log/messages #内核的消息以及各种服务的公共信息 > > ​ /var/log/dmesg #系统启动过程信息 > > ​ /var/log/cron #cron计划任务相关信息 > > ​ /var…...

hyper-v server服务器部署远程访问(我目前环境:hyper-v服务器+路由器+公网ip)

Hyper-v server部署(裸金属方式) 系统镜像下载安装# 下载地址:17763.737.190906-2324.rs5_release_svc_refresh_SERVERHYPERCORE_OEM_x64FRE_zh-cn_1.iso 安装的过程很简单,和安装Windows操作系统没啥区别,这里就不记录了。 安装过程可参考:安装Hyper-v Server 2016 部…...

【区块链安全 | 第三十七篇】合约审计之获取私有数据(一)

文章目录 私有数据访问私有数据实例存储槽Solidity 中的数据存储方式1. storage(持久化存储)定长数组变长数组2. memory(临时内存)3. calldata可见性关键字私有数据存储风险安全措施私有数据 私有数据(Private Data)通常指的是只对特定主体可见或可访问的数据,在区块链…...

项目管理(高软56)

系列文章目录 项目管理 文章目录 系列文章目录前言一、进度管理二、配置管理三、质量四、风险管理五、真题总结 前言 本节主要讲项目管理知识&#xff0c;这些知识听的有点意思啊。对于技术人想创业&#xff0c;单干的都很有必要听听。 一、进度管理 二、配置管理 三、质量 四…...

程序化广告行业(79/89):技术革新与行业发展脉络梳理

程序化广告行业&#xff08;79/89&#xff09;&#xff1a;技术革新与行业发展脉络梳理 大家好&#xff01;一直以来&#xff0c;我都热衷于在技术领域不断探索&#xff0c;也深知知识共享对于进步的重要性。写这篇博客&#xff0c;就是希望能和大家一起深入研究程序化广告行业…...

零基础上手Python数据分析 (13):DataFrame 数据合并与连接 - 整合多源数据,构建完整分析视图

写在前面 —— 告别 VLOOKUP 烦恼,掌握 Pandas 合并连接利器,轻松整合分散数据 在前面的博客中,我们学习了如何读取数据、清洗数据、选取数据。 现在,我们已经能够处理单个 DataFrame 中的数据了。 然而,在实际的数据分析项目中,数据往往不是存储在一个单独的文件或表格…...

解决OBS里的鼠标太小|OBS鼠标尺寸问题

在进行OBS录制时&#xff0c;不少用户可能会被鼠标显示问题所困扰。比如&#xff0c;录制时鼠标在画面中尺寸过大&#xff0c;影响视觉效果&#xff1b;或是出现两个鼠标指针&#xff0c;显得杂乱无章。其实&#xff0c;借助一款名为Custom cursor的工具&#xff0c;这些问题便…...

OpenCV边缘检测方法详解

文章目录 引言一、边缘检测基础概念边缘类型 二、OpenCV中的边缘检测方法1. Sobel算子2. Scharr算子3. Laplacian算子4. Canny边缘检测 三、性能比较与选择建议四、总结 引言 边缘检测是计算机视觉和图像处理中的基础技术&#xff0c;它能有效识别图像中物体的边界&#xff0c…...

寻找最大美丽数

# 输入&#xff1a;nums1 [4,2,1,5,3], nums2 [10,20,30,40,50], k 2 # 输出&#xff1a;[80,30,0,80,50] import random class Solution:def findMaxSum(self, nums1, nums2, k):hash_table []sum1 0data []print(**31,\n,\t数据)for key,values in enumerate(nums1):da…...

Linux:shell运行原理+权限

1.shell的运行原理 如果我们打开了命令终端或者是xshell进行远程登录服务器&#xff0c;就会看到命令行&#xff0c;如下图所示&#xff1a; 这个命令行本身也是系统中一个运行起来的程序&#xff0c;它用来接收用户的输入&#xff0c;帮用户来执行指令&#xff0c;将运行结果展…...

跨站请求是什么?

介绍 跨站请求&#xff08;Cross-Site Request&#xff09;通常是指浏览器在访问一个网站时&#xff0c;向另一个域名的网站发送请求的行为。这个概念在 Web 安全中非常重要&#xff0c;尤其是在涉及到“跨站请求伪造&#xff08;CSRF&#xff09;”和“跨域资源共享&#xff…...

【LeetCode Solutions】LeetCode 160 ~ 165 题解

CONTENTS LeetCode 160. 相交链表&#xff08;简单&#xff09;LeetCode 162. 寻找峰值&#xff08;中等&#xff09;LeetCode 164. 最大间距&#xff08;中等&#xff09;LeetCode 165. 比较版本号&#xff08;中等&#xff09; LeetCode 160. 相交链表&#xff08;简单&#…...

Openssl升级至openssl9.8p1含全部踩坑内容

1、安装依赖包基础条件 yum install gcc yum install gcc-c yum install perl yum install perl-IPC-Cmd yum install pam yum install pam-devel sudo yum install perl-Data-Dumper 问题一&#xff1a;提示yum不可用 镜像源问题更换阿里源即可 wget -O /etc/yum.repos.d/…...

ASP.NET Core 性能优化:内存缓存

文章目录 前言一、什么是缓存二、内存缓存三、使用内存缓存1&#xff09;注册内存缓存服务2&#xff09;注入与基本使用3&#xff09;高级用法GetOrCreate&#xff08;避免缓存穿透&#xff09;异步方法&#xff1a;GetOrCreateAsync&#xff08;避免缓存穿透&#xff09;两种过…...

二战蓝桥杯所感

&#x1f334; 前言 今天是2025年4月12日&#xff0c;第十六届蓝桥杯结束&#xff0c;作为二战的老手&#xff0c;心中还是颇有不甘的。一方面&#xff0c;今年的题目比去年简单很多&#xff0c;另一方面我感觉并没有把能拿的分都拿到手&#xff0c;这是我觉得最遗憾的地方。不…...

屏幕模块解析

通信协议 SPI 引脚定义 GPIO说明引脚配置SCK时钟线推挽输出MOSI主机输出、从机输入推挽输出MISO主机输入、从机输出浮空/上拉输入:没有开启数据传输时为高阻态SS片选推挽输出CPOL时钟极性0:空闲时SCK为低电平 1:空闲时SCK为高电平 CPHA时钟相位0:主从SCK第一个边沿输入1bi…...

查看手机在线状态,保障设备安全运行

手机作为人们日常生活中不可或缺的工具&#xff0c;承载着沟通、工作、娱乐等多种功能。保障手机设备的安全运行是我们每个人都非常重要的任务&#xff0c;而了解手机的在线状态则是其中的一环。通过挖数据平台提供的在线查询工具&#xff0c;我们可以方便快捷地查询手机号的在…...

#关于数据库中的时间存储

✅ 一、是否根据“机器当前时区”得到本地时间再转 UTC&#xff1f; 结论&#xff1a;是的&#xff0c;但仅对 TIMESTAMP 字段生效。 数据库&#xff08;如 MySQL&#xff09;在插入 TIMESTAMP 类型数据时&#xff1a; 使用当前会话的时区&#xff08;默认跟随系统时区&#…...

第16届蓝桥杯省赛python B组个人题解

文章目录 前言ABCDEFGH 前言 仅个人回忆&#xff0c;不保证正确性 貌似都是典题&#xff0c;针对python的长代码模拟题也没有&#xff0c;一小时速通了&#xff0c;希望不要翻车。 更新&#xff1a;B、G翻车了。。 A 答案&#xff1a;103 B 应该是按长度排序&#xff0c;然后…...

lvs+keepalived+dns高可用

1.配置dns相关服务 1.1修改ip地址主机名 dns-master: hostnamectl hostname lvs-master nmcli c modify ens160 ipv4.method manual ipv4.addresses 10.10.10.107/24 ipv4.gateway 10.10.10.2 ipv4.dns 223.5.5.5 connection.autoconnect yes nmcli c up ens160dns-salve: h…...