【KWDB 创作者计划】_ruby基础语法
以下是 Ruby 基础语法的简明总结,适合快速入门:
一、变量与常量
1. 局部变量
小写字母或下划线开头,作用域为当前代码块。
name = "Alice"
_age = 20
//局部变量附加:{{{{
声明与命名规则
-
命名格式
- 以小写字母或下划线
_开头,如name、_count。 - 后续字符可包含字母、数字和下划线。
- 避免与 Ruby 关键字(如
class、def)冲突。
- 以小写字母或下划线
-
声明方式
- 通过赋值
=隐式声明,无需显式类型。
age = 25 # 声明局部变量 age _message = "Hello" # 声明局部变量 _message - 通过赋值
作用域规则
-
代码块内外的可见性
-
块参数会遮蔽外部变量:
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
-
-
方法内的局部变量
-
方法内部变量对外不可见:
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
-
-
条件与循环中的变量
-
即使条件未执行,变量也会被声明(初始化为
nil):if falsea = 1 # 代码未执行,但变量 a 已声明 end puts a # 输出 nil -
循环(如
while)不创建新作用域:i = 0 while i < 3inner = ii += 1 end puts inner # 输出 2
-
变量遮蔽与覆盖
-
内部作用域遮蔽外部变量
x = 100 1.times dox = 200 # 直接修改外部变量 xy = 300 # 声明新变量 y(作用域在块内) end puts x # 输出 200 puts y # NameError: undefined local variable -
方法参数与局部变量同名
def demo(x)x = 20 # 修改的是参数 x,不影响外部变量puts x # 输出 20 end x = 10 demo(x) puts x # 输出 10
特殊场景
-
顶层作用域的局部变量
- 在文件或交互式环境(如 irb)顶层定义的局部变量,作用域为当前文件或会话:
top_var = "顶层变量" def show_top_varputs top_var # NameError: undefined local variable end show_top_var
- 在文件或交互式环境(如 irb)顶层定义的局部变量,作用域为当前文件或会话:
-
类/模块定义中的局部变量
- 在类或模块定义中声明的局部变量,仅在该定义范围内有效:
class MyClassclass_var = "类定义内的局部变量"def self.show_varputs class_var # NameError: undefined local variableend end
- 在类或模块定义中声明的局部变量,仅在该定义范围内有效:
最佳实践
- 避免变量遮蔽:谨慎使用与外部作用域同名的变量。
- 限制作用域:在最小必要范围内定义变量,减少副作用。
- 明确命名:使用有意义的变量名(如
user_count而非uc)。
总结
| 场景 | 行为 |
|---|---|
| 块内无参数赋值 | 可读写外部变量 |
| 块带同名参数 | 遮蔽外部变量,内部操作不影响外部 |
| 方法内部变量 | 仅在方法内有效,外部不可见 |
| 条件/循环中的变量 | 即使代码未执行,变量也会被声明(值为 nil) |
| 类定义中的变量 | 仅在类定义过程中有效,类方法无法访问 |
理解局部变量的作用域规则是编写可维护 Ruby 代码的基础,尤其在处理复杂逻辑时能避免意外的变量污染或覆盖。
//局部变量附加结束}}}}
2. 实例变量
以 @ 开头,属于对象实例。
@name = "Bob"
//实例变量附加:{{{{
实例变量(Instance Variables)是面向对象编程的核心概念,用于存储对象的状态。以下是其详细规则和使用方法:
定义与基本特性
-
命名规则
- 以
@符号开头,如@name、@age。 - 后续字符可包含字母、数字和下划线。
- 默认值为
nil(未显式赋值时)。
- 以
-
作用域
- 属于对象实例:每个对象的实例变量独立存在。
- 在类的方法中可访问:在类的任何实例方法中均可读写。
声明与访问
- 直接赋值
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 类,并演示了如何创建对象实例和调用方法。以下是逐行解释:
- 定义
Person类
class Person# 类体开始
end
class Person:定义一个名为Person的类。- Ruby 的类名需以 大写字母开头,采用驼峰式命名。
- 构造方法
initialize
def initialize(name)@name = name # 初始化实例变量 @name
end
initialize:类的构造方法,在调用Person.new时自动执行。name:构造方法的参数,用于接收外部传入的值。@name = name:将参数name赋值给实例变量@name。@name:以@开头的变量是实例变量,属于对象实例的私有状态。
- 实例方法
greet
def greet"Hello, #{@name}!" # 使用实例变量 @name 拼接字符串
end
greet:定义一个名为greet的实例方法。#{@name}:字符串插值语法,将@name的值嵌入字符串中。- 方法返回值为字符串(Ruby 中方法的最后一行的值会被自动返回)。
- 创建对象实例
person = Person.new("Alice")
Person.new("Alice"):调用Person类的new方法创建实例。new方法会触发initialize方法,并将"Alice"作为参数传递。- 此时
@name被赋值为"Alice"。
person:变量指向新创建的Person实例对象。
- 调用方法并输出结果
puts person.greet # => "Hello, Alice!"
person.greet:调用person实例的greet方法。- 方法返回字符串
"Hello, Alice!"。
- 方法返回字符串
puts:输出字符串到控制台。
//class Person代码的解释结束
- 通过访问器方法
Ruby 提供快捷方法生成getter和setter:
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 提供了三个核心方法简化操作:
三种属性访问器
-
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(无写方法) -
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(无读方法) -
attr_accessor
生成 读写方法(getter + setter),最常用。class Productattr_accessor :price # 生成读方法和写方法def initialize(price)@price = priceend endproduct = Product.new(100) product.price = 150 puts product.price # => 150
访问器的底层原理
-
手动实现等效代码
class User# attr_reader :name 的等效代码def name@nameend# attr_writer :name 的等效代码def name=(value)@name = valueend end -
动态生成方法
attr_*方法本质是通过元编程动态定义方法:class Classdef my_attr_reader(name)define_method(name) doinstance_variable_get("@#{name}")endend end
高级用法与技巧
-
批量定义访问器
class Personattr_accessor :name, :age, :gender # 多个属性 end -
添加自定义逻辑
class Temperatureattr_reader :celsiusdef celsius=(value)raise "温度不能低于绝对零度" if value < -273.15@celsius = valueend endtemp = Temperature.new temp.celsius = -300 # RuntimeError -
结合初始化方法
class Bookattr_accessor :title, :authordef initialize(title, author)@title = title@author = authorend endbook = Book.new("Ruby指南", "松本行弘") book.title = "Ruby高级编程" -
继承行为
父类的访问器方法会被子类继承:class Admin < User end admin = Admin.new(1) admin.email = "admin@example.com" # 正常执行(继承 attr_accessor)
//访问器方法代码解释 结束
实例变量的特性
- 封装性
- 实例变量默认是 私有 的,外部无法直接访问。
- 必须通过方法暴露(如
attr_accessor)。
- 动态增删
可在运行时动态添加或删除实例变量:
obj = Object.new
obj.instance_variable_set(:@x, 10) # 动态添加 @x
puts obj.instance_variable_get(:@x) # => 10
obj.remove_instance_variable(:@x) # 删除 @x
//动态增删附加 开始:
这段 Ruby 脚本演示了如何通过反射机制 动态管理实例变量,
代码逐行解析
- 创建新对象
obj = Object.new
- 作用:创建一个
Object类的匿名实例。 - 对象状态:此时
obj没有任何预定义的实例变量。
- 动态添加实例变量
@x
obj.instance_variable_set(:@x, 10)
instance_variable_set方法- 功能:直接为对象设置实例变量。
- 参数:
- 第一个参数:符号形式的变量名(必须包含
@,如:@x)。 - 第二个参数:变量值(可以是任意对象)。
- 第一个参数:符号形式的变量名(必须包含
- 结果:对象
obj新增实例变量@x,值为10。
- 读取实例变量
@x的值
puts obj.instance_variable_get(:@x) # => 10
instance_variable_get方法- 功能:直接读取对象的实例变量值。
- 参数:符号形式的变量名(如
:@x)。 - 返回值:变量的当前值,若变量不存在则返回
nil。
- 删除实例变量
@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 处理 |
使用场景
-
动态对象构造
在运行时根据条件动态添加属性:data = { name: "Alice", age: 20 } obj = Object.new data.each { |key, value| obj.instance_variable_set("@#{key}", value) } -
元编程和框架开发
在编写灵活的程序结构时(如 ORM、序列化工具):class Serializerdef serialize(obj)obj.instance_variables.each_with_object({}) do |var, hash|hash[var] = obj.instance_variable_get(var)endend end -
调试和探索性编程
快速查看或修改对象内部状态: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
// 动态增删附加 结束
- 与类变量的对比
实例变量 (@var) | 类变量 (@@var) | |
|---|---|---|
| 作用域 | 对象实例内 | 类及其所有实例共享 |
| 继承行为 | 子类对象不继承父类实例变量 | 子类共享父类的类变量 |
高级用法
5. 元编程访问
class Dogdef initialize(name)@name = nameend
enddog = Dog.new("Buddy")# 获取所有实例变量名
dog.instance_variables # => [:@name]# 检查是否存在实例变量
dog.instance_variable_defined?(:@name) # => true
- 在模块中定义实例变量
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"]
注意事项
-
避免未初始化访问
实例变量未赋值时为nil,需注意空值问题:class Productdef print_price"Price: #{@price}" # @price 未初始化时为 nilend endProduct.new.print_price # => "Price: " -
命名冲突
子类可能意外覆盖父类的实例变量:class Animaldef initialize@name = "Animal"end endclass Cat < Animaldef initialize@name = "Cat" # 覆盖父类的 @nameend end
总结
| 场景 | 实例变量的行为 |
|---|---|
| 对象初始化 | 通过 initialize 方法赋值 |
| 方法间共享 | 同一对象的实例方法均可访问 |
| 动态管理 | 支持运行时增删 |
| 封装性 | 必须通过方法暴露给外部 |
实例变量是 Ruby 面向对象的核心机制,合理使用它们可以高效管理对象状态!
//实例变量附加结束}}}}
3. 类变量
以 @@ 开头,属于整个类。
@@count = 0
// 类变量 附加开始{{{{
在 Ruby 中,类变量(Class Variables)是一种特殊类型的变量,用于在类层级共享数据。
定义与基本特性
-
命名规则
- 以
@@开头,如@@count、@@config。 - 后续字符遵循变量命名规范(字母、数字、下划线)。
- 必须显式初始化(否则抛出
NameError)。
- 以
-
作用域
- 类层级共享:类变量属于类本身,被所有实例和子类共享。
- 全局可见:在类定义、实例方法、类方法中均可访问。
基本用法示例
1. 类变量初始化与访问
class Counter@@count = 0 # 初始化类变量def self.increment@@count += 1enddef self.total@@countend
endCounter.increment
Counter.increment
puts Counter.total # => 2
- 实例方法访问类变量
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
类变量的继承行为
- 子类共享父类的类变量
class Parent@@value = 100def self.value@@valueend
endclass Child < Parentdef self.change_value@@value = 200end
endChild.change_value
puts Parent.value # => 200(父类的类变量被子类修改)
- 所有子类共享同一变量
class A@@list = []
endclass B < A; end
class C < A; endB.class_variable_get(:@@list) << "item"
puts C.class_variable_get(:@@list) # => ["item"]
类变量的替代方案:类实例变量
由于类变量的共享特性容易导致意外修改,Ruby 开发者常使用 类实例变量 作为替代:
- 类实例变量特性
- 以
@开头,属于类对象(而非类本身)。 - 不被子类继承,每个类独立拥有自己的副本。
- 通过类方法中的
attr_accessor定义。
- 示例对比
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
类变量使用场景
| 场景 | 示例 |
|---|---|
| 全局类级计数器 | 统计实例数量、方法调用次数 |
| 共享配置 | 数据库连接、日志级别设置 |
| 缓存数据 | 存储类级别的计算结果或临时数据 |
注意事项与陷阱
-
初始化位置
类变量必须在类或模块内部初始化(不能在其他作用域)。class Demo@@value = 0 # 正确:在类体内初始化 end# @@value = 0 # 错误:顶层作用域无法初始化类变量 -
线程安全问题
类变量在多线程环境中可能引发竞态条件,需加锁保护:class Counter@@mutex = Mutex.new@@count = 0def self.safe_increment@@mutex.synchronize { @@count += 1 }end end -
避免过度共享
类变量的全局性容易导致代码耦合,应谨慎使用。
总结对比
| 特性 | 类变量 (@@var) | 类实例变量 (@var) |
|---|---|---|
| 作用域 | 类及其所有子类共享 | 仅在定义它的类中有效 |
| 继承行为 | 子类修改影响父类和其他子类 | 不继承,每个类独立 |
| 初始化位置 | 必须在类或模块内部 | 可在类方法或类体内初始化 |
| 适用场景 | 需要跨继承树共享数据 | 需要类级别的私有状态 |
//类变量 附加结束}}}}
4. 全局变量
以 $ 开头,作用域全局。
$debug_mode = true
//全局变量附件开始
全局变量(Global Variables)是作用域覆盖整个程序(包括所有模块、类和方法的变量)。
全局变量的核心规则
-
命名规则
- 以
$开头,如$counter、$logger。 - 后续字符遵循变量命名规范(字母、数字、下划线)。
- 以
-
作用域
- 全局可见:在程序的任何位置(包括类、模块、方法、块)均可读写。
-
默认值
- 未初始化的全局变量值为
nil。
- 未初始化的全局变量值为
基本用法示例
- 声明与赋值
$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"
- 预定义全局变量
Ruby 有一些内置的全局变量(如$!、$@),用于访问系统信息或异常上下文:
begin1 / 0
rescue => eputs $! # 输出最后抛出的异常信息(等同 e.message)puts $@ # 输出异常堆栈跟踪(等同 e.backtrace)
end
全局变量的优缺点
优点
- 快速共享数据:无需通过参数传递,直接跨作用域访问。
- 临时调试工具:快速记录程序状态。
缺点
- 破坏封装性:导致代码耦合,难以追踪修改来源。
- 命名冲突风险:全局变量名可能被意外覆盖。
- 维护困难:大型项目中难以管理。
使用场景(谨慎选择!)
| 场景 | 示例 |
|---|---|
| 跨模块共享配置 | 日志级别、环境变量 |
| 临时调试或性能监控 | 记录方法调用次数 |
| 单例模式简单实现 | 全局唯一的数据库连接对象 |
替代方案(推荐优先使用)
-
常量(全大写命名)
module ConfigAPP_NAME = "MyApp" # 常量,可被修改但会警告 endputs Config::APP_NAME -
类/模块变量
class AppState@@instance_count = 0 # 类变量def self.increment@@instance_count += 1end end -
单例模式
require 'singleton'class Loggerinclude Singletonattr_accessor :leveldef initialize@level = "INFO"end endLogger.instance.level = "DEBUG"
注意事项
-
避免滥用:仅在无其他替代方案时使用。
-
命名规范:使用明确的前缀(如
$myapp_logger),避免与内置全局变量冲突。 -
线程安全:多线程环境中需加锁保护。
$counter = 0 $counter_mutex = Mutex.newdef increment_counter$counter_mutex.synchronize { $counter += 1 } end -
重置全局变量:可通过赋值
nil释放资源。$db_connection = nil # 断开数据库连接并释放内存
内置全局变量
| 变量 | 用途 |
|---|---|
$! | 最后抛出的异常对象 |
$@ | 最后异常的堆栈跟踪信息 |
$? | 最后执行的子进程状态 |
$0 | 当前执行的脚本文件名 |
$: | Ruby 的加载路径(等同 $LOAD_PATH) |
$_ | 最后读取的输入行(如 gets 结果) |
最佳实践:除非必要,优先使用常量、类变量或依赖注入模式替代全局变量。
//全局变量附件结束
5. 常量
全大写字母,约定不可修改(修改会警告)。
PI = 3.14159
//常量附加开始
常量(Constants)是一种用于存储固定值的标识符,其命名以大写字母开头,通常用于定义配置、枚举值或全局共享数据。
常量的基本规则
-
命名规范
- 必须以大写字母开头(如
PI、MAX_SIZE)。 - 约定全大写加下划线(如
DEFAULT_TIMEOUT),但也可用驼峰式(如AppConfig)。
- 必须以大写字母开头(如
-
赋值与修改
- 应保持不可变:Ruby 允许修改常量,但会发出警告。
- 重新赋值触发警告:
PI = 3.14 PI = 3.14159 # 输出 warning: already initialized constant PI
-
作用域
- 定义在类、模块或顶层作用域。
- 通过命名空间访问(如
MyClass::CONST)。
常量的定义与访问
- 顶层常量(全局可见)
APP_NAME = "MyApp" # 顶层常量class Userdef show_app_nameAPP_NAME # 直接访问end
endputs APP_NAME # => "MyApp"
- 类/模块内的常量
class MathUtilsPI = 3.14159 # 类常量def circle_area(radius)PI * radius ** 2end
endputs MathUtils::PI # => 3.14159
- 模块中的常量
module ColorsRED = "#FF0000"
endclass Carinclude Colors
endputs Car::RED # => "#FF0000"(通过 include 引入)
常量的查找规则
- 继承链查找
子类会继承父类的常量,但可覆盖:
class ParentVALUE = 100
endclass Child < ParentVALUE = 200 # 覆盖父类常量
endputs Parent::VALUE # => 100
puts Child::VALUE # => 200
- 作用域解析运算符
::
module OuterCONST = "Outer"module InnerCONST = "Inner"def self.showputs CONST # => "Inner"puts Outer::CONST # => "Outer"endend
endOuter::Inner.show
常量 vs 类变量
| 特性 | 常量 (CONST) | 类变量 (@@var) |
|---|---|---|
| 命名规则 | 大写字母开头 | @@ 开头 |
| 可修改性 | 可修改(有警告) | 可随意修改 |
| 作用域 | 类/模块或全局 | 类及其子类共享 |
| 继承行为 | 子类可覆盖 | 子类共享同一变量 |
最佳实践
-
避免修改常量
如需可变配置,改用类方法或单例模式:class Configdef self.timeout@timeout ||= 10 # 可修改且无警告end end -
冻结常量(不可变对象)
防止常量引用的对象被修改:COLORS = { red: "#FF0000" }.freeze COLORS[:red] = "#FF1234" # RuntimeError: can't modify frozen Hash -
使用模块组织常量
module SettingsTIMEOUT = 30API_KEY = "secret" endputs Settings::API_KEY
动态操作常量
- 动态定义与访问
class Dynamicconst_set(:MAX, 100) # 定义常量 MAXputs const_get(:MAX) # => 100puts constants.include?(:MAX) # => true
end
- 检查常量存在性
if MyClass.const_defined?(:VERSION)puts MyClass::VERSION
end
常见错误
-
未初始化的常量
puts UNDEFINED_CONST # NameError: uninitialized constant UNDEFINED_CONST -
命名空间遗漏
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)
- 表示方式
- 十进制:默认写法,如
123。 - 二进制:以
0b或0B开头,如0b1010(十进制的 10)。 - 八进制:以
0或0o开头,如0o755(十进制的 493)。 - 十六进制:以
0x开头,如0xFF(十进制的 255)。
- 自动大整数支持
Ruby 自动处理整数溢出,小整数(Fixnum)和大整数(Bignum)无缝切换:
a = 123 # => 123(Fixnum)
b = 1234567890 * 9876543210 # => 12193263113702179500(Bignum)
- 常用方法
| 方法 | 说明 | 示例 |
|---|---|---|
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²³)。
- 精度问题与解决方案
浮点数计算可能因精度丢失导致误差:
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
数值运算
- 基本运算符
| 运算符 | 说明 | 示例 |
|---|---|---|
+ | 加法 | 5 + 3 => 8 |
- | 减法 | 5 - 3 => 2 |
* | 乘法 | 5 * 3 => 15 |
/ | 除法 | 5 / 2 => 2(整数除法)5.to_f / 2 => 2.5 |
% | 取模 | 5 % 2 => 1 |
** | 幂运算 | 2 ** 3 => 8 |
- 除法行为
- 整数除法:结果自动向下取整。
7 / 3 # => 2 - 浮点除法:强制转换为浮点数。
7.to_f / 3 # => 2.333... 7 / 3.0 # => 2.333...
- 链式比较
Ruby 支持数学中的链式比较:
1 < 2 < 3 # => true
5 <= x <= 10 # 判断 x 是否在 5 到 10 之间
类型转换
| 目标类型 | 方法 | 示例 |
|---|---|---|
| 整数转浮点 | to_f | 5.to_f => 5.0 |
| 浮点转整数 | to_i(截断) | 3.9.to_i => 3 |
| 四舍五入 | round | 3.6.round => 4 |
| 向上取整 | ceil | 3.2.ceil => 4 |
| 向下取整 | floor | 3.9.floor => 3 |
| 字符串转数值 | to_i, to_f | "42".to_i => 42 |
实用技巧
- 随机数生成
rand(10) # 生成 0~9 的随机整数
rand(5.0..10.0) # 生成 5.0 到 10.0 的随机浮点数
- 数值格式化
sprintf("%.2f", 3.1415) # => "3.14"
3.1415.round(2) # => 3.14(四舍五入保留两位小数)
- 数值范围检查
(1..100).cover?(50) # => true(检查数值是否在范围内)
-
字符串(String)
单引号(不转义)或双引号(支持转义和插值)。str1 = 'Hello \n World' # 输出换行符 str2 = "Hello #{name}" # 插值:Hello Alice -
符号(Symbol)
轻量级字符串,以:开头,常用于哈希键。:user_id -
数组(Array)
有序集合,通过索引访问。nums = [1, 2, 3] nums[0] # => 1 -
哈希(Hash)
键值对集合,键可以是任意对象。person = { name: "Alice", age: 20 } person[:name] # => "Alice" -
范围(Range)
表示连续区间,常用于迭代。(1..5).each { |n| puts n } # 1到5 (1...5).each { |n| puts n } # 1到4
三、运算符
-
算术运算符
+,-,*,/,%,**(幂运算)。2 ** 3 # => 8 10 % 3 # => 1 -
比较运算符
==,!=,>,<,>=,<=,<=>(返回 -1, 0, 1)。5 <=> 3 # => 1(5 > 3) -
逻辑运算符
&&,||,!(也可用and,or,not,但优先级不同)。true && false # => false -
赋值运算符
=,+=,-=,*=,/=,%=。x = 5 x += 3 # => 8
四、控制结构
-
条件判断
# if/elsif/else if age >= 18puts "Adult" elsif age > 0puts "Child" elseputs "Invalid" end# 三元运算符 result = (score > 60) ? "Pass" : "Fail" -
循环
# 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 -
迭代器
# each 方法 (1..3).each { |n| puts n }# map 方法 doubled = [1, 2, 3].map { |n| n * 2 } # => [2, 4, 6]
五、方法定义
-
基本语法
def greet(name)"Hello, #{name}!" end greet("Ruby") # => "Hello, Ruby!" -
默认参数
def add(a, b = 1)a + b end add(3) # => 4 add(3, 5) # => 8 -
可变参数
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
七、注释
-
单行注释
# 这是一个注释 -
多行注释
=begin 这是一个多行注释 可以写多行内容 =end
八、特殊语法
-
% 符号快捷语法
%w[apple banana cherry] # => ["apple", "banana", "cherry"](字符串数组) %i[red green blue] # => [:red, :green, :blue](符号数组) -
并行赋值
a, b = 1, 2 # a=1, b=2 a, b = b, a # 交换值:a=2, b=1
九、代码块(Block)
-
使用
{}或do...end# 单行用 {} [1, 2, 3].each { |n| puts n }# 多行用 do...end [1, 2, 3].each do |n|puts "Number: #{n}" end -
自定义接受块的方法
def repeat(times)times.times { yield } # yield 调用块 endrepeat(3) { puts "Hello!" } # 输出 3 次 Hello
十、常用方法示例
-
字符串操作
"ruby".upcase # => "RUBY" "HELLO".downcase # => "hello" " test ".strip # => "test" -
数组操作
[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 | 多条件匹配 |
when | case 语句的分支条件 |
then | 简化条件语法 |
end | 结束代码块 |
循环与迭代
| 关键字 | 说明 |
|---|---|
while | 条件循环 |
until | 反向条件循环 |
for | 遍历循环(较少使用) |
in | 用于 for 或 case |
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 | 模式匹配分支 |
注意:
-
非关键字但需谨慎使用:
puts、gets等是全局方法,而非关键字。
proc、lambda是类或方法,可被覆盖(但强烈建议不要这样做)。 -
版本差异:
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 基础语法的简明总结,适合快速入门: 一、变量与常量 1. 局部变量 小写字母或下划线开头,作用域为当前代码块。 name "Alice" _age 20//局部变量附加:{{{{ 声明与命名规则 命名格式 以小写字母或下划线…...
Python Cookbook-5.15 根据姓的首字母将人名排序和分组
任务 想将一组人名写入一个地址簿,同时还希望地址簿能够根据姓的首字母进行分组,且按照字母顺序表排序。 解决方案 Python 2.4 的新 itertools.groupby 函数使得这个任务很简单: import itertools def qroupnames(name_iterable):sorted_names sort…...
2025 蓝桥杯省赛c++B组个人题解
声明 本题解为退役蒻苟所写,不保证正确性,仅供参考。 花了大概2个半小时写完,感觉比去年省赛简单,难度大概等价于 codeforces dv4.5 吧 菜鸡不熟悉树上背包,调了一个多小时 题目旁边的是 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文档很容易,但是当word文档需要插入动态图片,带循环数据,且含有富文本时解决起来相对比较复杂,但是使用Xdocreport可以轻易解决。 Xdocreport既可以实现文档填充也可以实现文档转换,此处…...
运行一次性任务与定时任务
运行一次性任务与定时任务 文章目录 运行一次性任务与定时任务[toc]一、使用Job运行一次性任务1.创建一次性任务2.测试一次性任务3.删除Job 二、使用CronJob运行定时任务1.创建定时任务2.测试定时任务3.删除CronJob 一、使用Job运行一次性任务 1.创建一次性任务 (…...
解决VS2022中scanf报错C4996
这个的原因是因为新版的VS认为scanf不安全,要去使用scanf_s,但在C语言中就需要scanf,所以我们只要以以下步骤解决就可以了。 只要加入宏定义即可 #define _CRT_SECURE_NO_WARNINGS 因为本人已经很少写小案例了,所以就用这个办法…...
当当平台商品详情接口设计与调用指南
当当平台商品详情接口设计与调用指南 接口名称 GET /api/product/detail 图书商品核心信息查询接口 请求参数说明 参数名称 类型 是否必填 说明 isbn string 是 国际标准书号(支持13位/10位) product_id string 否 平台内部商品编号(与…...
sql server分析表大小
使用自动存储过程查询 EXEC sp_spaceused YourTableName; rows:表中的行数。reserved:表占用的总空间(包括数据和索引)。data:表数据占用的空间。index_size:索引占用的空间。unused:未使用的空…...
《AI大模型应知应会100篇》第13篇:大模型评测标准:如何判断一个模型的优劣
第13篇:大模型评测标准:如何判断一个模型的优劣 摘要 近年来,大语言模型(LLMs)在自然语言处理、代码生成、多模态任务等领域取得了显著进展。然而,随着模型数量和规模的增长,如何科学评估这些模…...
Linux基础9
一、日志管理 > 日志配置文件: > > /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)
系列文章目录 项目管理 文章目录 系列文章目录前言一、进度管理二、配置管理三、质量四、风险管理五、真题总结 前言 本节主要讲项目管理知识,这些知识听的有点意思啊。对于技术人想创业,单干的都很有必要听听。 一、进度管理 二、配置管理 三、质量 四…...
程序化广告行业(79/89):技术革新与行业发展脉络梳理
程序化广告行业(79/89):技术革新与行业发展脉络梳理 大家好!一直以来,我都热衷于在技术领域不断探索,也深知知识共享对于进步的重要性。写这篇博客,就是希望能和大家一起深入研究程序化广告行业…...
零基础上手Python数据分析 (13):DataFrame 数据合并与连接 - 整合多源数据,构建完整分析视图
写在前面 —— 告别 VLOOKUP 烦恼,掌握 Pandas 合并连接利器,轻松整合分散数据 在前面的博客中,我们学习了如何读取数据、清洗数据、选取数据。 现在,我们已经能够处理单个 DataFrame 中的数据了。 然而,在实际的数据分析项目中,数据往往不是存储在一个单独的文件或表格…...
解决OBS里的鼠标太小|OBS鼠标尺寸问题
在进行OBS录制时,不少用户可能会被鼠标显示问题所困扰。比如,录制时鼠标在画面中尺寸过大,影响视觉效果;或是出现两个鼠标指针,显得杂乱无章。其实,借助一款名为Custom cursor的工具,这些问题便…...
OpenCV边缘检测方法详解
文章目录 引言一、边缘检测基础概念边缘类型 二、OpenCV中的边缘检测方法1. Sobel算子2. Scharr算子3. Laplacian算子4. Canny边缘检测 三、性能比较与选择建议四、总结 引言 边缘检测是计算机视觉和图像处理中的基础技术,它能有效识别图像中物体的边界,…...
寻找最大美丽数
# 输入:nums1 [4,2,1,5,3], nums2 [10,20,30,40,50], k 2 # 输出:[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进行远程登录服务器,就会看到命令行,如下图所示: 这个命令行本身也是系统中一个运行起来的程序,它用来接收用户的输入,帮用户来执行指令,将运行结果展…...
跨站请求是什么?
介绍 跨站请求(Cross-Site Request)通常是指浏览器在访问一个网站时,向另一个域名的网站发送请求的行为。这个概念在 Web 安全中非常重要,尤其是在涉及到“跨站请求伪造(CSRF)”和“跨域资源共享ÿ…...
【LeetCode Solutions】LeetCode 160 ~ 165 题解
CONTENTS LeetCode 160. 相交链表(简单)LeetCode 162. 寻找峰值(中等)LeetCode 164. 最大间距(中等)LeetCode 165. 比较版本号(中等) LeetCode 160. 相交链表(简单&#…...
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 问题一:提示yum不可用 镜像源问题更换阿里源即可 wget -O /etc/yum.repos.d/…...
ASP.NET Core 性能优化:内存缓存
文章目录 前言一、什么是缓存二、内存缓存三、使用内存缓存1)注册内存缓存服务2)注入与基本使用3)高级用法GetOrCreate(避免缓存穿透)异步方法:GetOrCreateAsync(避免缓存穿透)两种过…...
二战蓝桥杯所感
🌴 前言 今天是2025年4月12日,第十六届蓝桥杯结束,作为二战的老手,心中还是颇有不甘的。一方面,今年的题目比去年简单很多,另一方面我感觉并没有把能拿的分都拿到手,这是我觉得最遗憾的地方。不…...
屏幕模块解析
通信协议 SPI 引脚定义 GPIO说明引脚配置SCK时钟线推挽输出MOSI主机输出、从机输入推挽输出MISO主机输入、从机输出浮空/上拉输入:没有开启数据传输时为高阻态SS片选推挽输出CPOL时钟极性0:空闲时SCK为低电平 1:空闲时SCK为高电平 CPHA时钟相位0:主从SCK第一个边沿输入1bi…...
查看手机在线状态,保障设备安全运行
手机作为人们日常生活中不可或缺的工具,承载着沟通、工作、娱乐等多种功能。保障手机设备的安全运行是我们每个人都非常重要的任务,而了解手机的在线状态则是其中的一环。通过挖数据平台提供的在线查询工具,我们可以方便快捷地查询手机号的在…...
#关于数据库中的时间存储
✅ 一、是否根据“机器当前时区”得到本地时间再转 UTC? 结论:是的,但仅对 TIMESTAMP 字段生效。 数据库(如 MySQL)在插入 TIMESTAMP 类型数据时: 使用当前会话的时区(默认跟随系统时区&#…...
第16届蓝桥杯省赛python B组个人题解
文章目录 前言ABCDEFGH 前言 仅个人回忆,不保证正确性 貌似都是典题,针对python的长代码模拟题也没有,一小时速通了,希望不要翻车。 更新:B、G翻车了。。 A 答案:103 B 应该是按长度排序,然后…...
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…...
