Ruby基础
大约 14 分钟
Ruby基础
命令行交互
命令行 输入
irb
- => 命令的返回值
- 直接输入
"Hello World"
:=> "Hello World"
puts("Hello World")
- "Hello World"
=> nil
puts 命令永远返回 nil
- 数学计算:
3+2
:=> 5
3**2
3的二次方
执行 ruby 文件
- ruby demo.rb
基础语法
- Ruby 文件扩展名
.rb
- 语句分隔符 分号(;)和 换行符(\n)
- Ruby 代码在行尾遇到运算符,比如 +、- 或 反斜杠(/),它们表示一个语句的延续
c = 1 +
8
puts(c)
=> 9
Ruby 标识符
- 变量、常量和方法的名称
- 可以包含字母、数字和下划线字符(_)
- 大小写敏感
- 保留字 不能用作标识符
保留字
Here Document
* 是指 建立多行字符串
* 在 << 之后,可以指定一个字符串或标识符来终止字符串,且当前行之后直到终止符为止的所有行是字符串的值
* 如果终止符使用引号括起,引号的类型决定了面向行的字符串类型。
注释
- 单行注释以 # 号开始
- 多行注释以 =begin 开始,以 =end 结束,这之间的所有字符或者语句都会被 Ruby 解释器忽略
# 这是注释
# 这也是注释 puts "Hello Ruby!"
# 这也是注释 puts "Hello Ruby!"
# 这还是注释
def hello
puts("Hello");
end
=begin
这是注释。 puts "Hello Ruby!"
这也是注释。puts "Hello Ruby!"
这也是注释。puts "Hello Ruby!"
这还是注释。puts "Hello Ruby!"
=end
编码
- 中文,早期Ruby版本 ruby文件头,要加utf-8标识,否则报错:
invalid multibyte char (US-ASCII)
**# -*- coding: UTF-8 -*-**
#coding=utf-8
- 较新Ruby版本,无需添加
#!/usr/bin/ruby -w
# -*- coding: UTF-8 -*-
puts "你好,世界!";
数据类型
数值类型
- Number:数值类型
- 整型( Integer )
- 如果在 31 位以内( 4 字节 ),那为 Fixnum 实例
- 如果超过,即为 Bignum 实例
- 整数前使用一个可选的前导符号, 一个可选的基础指标,后跟一串数字
0 对应 octal
八进制0x 对应 hex
十六进制0b 对应 binary
- 下划线字符在数字字符串中被忽略
123 # Fixnum 十进制
1_234 # Fixnum 带有下划线的十进制
- 用问号标记的转义序列的整数值
> ?\C-s #Control-s的值ASCII
=> "\u0013"
- ASCII 字符 的整数值
"a".ord
- 浮点型:是带有小数的数字
- 浮点数是类 Float 的对象
- 整型( Integer )
字符串类型
- 类 String 的对象
- 使用 序列 #{ expr } 来表示字符串中的参数或表达式
puts "a + b = #{ a + b}"
a + b = 3
转义字符
范围类型
- 表示一个区间
- 通过设置一个开始值和一个结束值来表示
- s..e 包含结束值
- s...e 不包含结束值
- Range.new
范围 (1..5) 意味着它包含值 1, 2, 3, 4, 5
特殊值
- true
- false
- nil
数据结构
数组
- 通过 [ ] 中以逗号分隔定义,且支持 range 定义
- 通过 [i] 索引访问
array_a = [1,2,3]
array_a[0] = 111
puts "打印数组元素0 : #{ array_a[0] }"
# 打印数组元素0 : 111
哈希表类型(Map)
- Ruby 哈希是在大括号内放置一系列键/值对,键和值之间使用逗号和序列 => 分隔
- 尾部的逗号会被忽略
- 哈希类对象Hash
- 任意创建方式
myhash = Hash.new
myhash = Hash.new( "month" )
myhash = Hash.new "month"
colors = { "red" => 0xf00, "green" => 0x0f0, "blue" => 0x00f }
puts colors["red"]
类对象方法
Ruby 是一种完美的面向对象编程语言
面向对象编程语言的特性包括:数据封装、数据抽象、多态性、继承
类可以看成是属性和函数的组合
关键字 class
关键字 end 终止一个类
Ruby 中类名必须以大写字母开头;
- 定义类
class ClassName
end #
- 创建对象
- new 方法
- new 传递参数用于初始化类变量
- 声明方法 initialize
class ClassName
def initialize(id, name, addr)
@cust_id = id
@cust_name = name
@cust_addr = addr
end
def aa
puts "aa"
end
end
obj1 = ClassName.new
obj1 = ClassName.new(2, "百度", "北京市海淀区")
obj1.aa # 调用方法
to_s 方法
- 任何类都有一个 to_s 实例方法来返回对象的字符串表示形式
class Box
# 构造器方法
def initialize(w,h)
@width, @height = w, h
end
# 定义 to_s 方法
def to_s
"(w:#@width,h:#@height)" # 对象的字符串格式
end
end
# 创建对象
box = Box.new(6, 8)
# 自动调用 to_s 方法
puts "String representation of box is : #{box}"
String representation of box is : (w:6,h:8)
访问控制
- Public 方法: Public 方法可被任意对象调用。 默认情况下,方法都是 public 的,除了 initialize 方法总是 private 的。
- Private 方法: Private 方法不能从类外部访问或查看,只有类方法可以访问私有成员
- Protected 方法: Protected 方法只能被类及其子类的对象调用。访问也只能在类及其子类内部进行
类的继承
- 继承,是面向对象编程中最重要的概念之一。继承允许我们根据另一个类定义一个类,这样使得创建和维护应用程序变得更加容易。
- Ruby 不支持多继承,但是 Ruby 支持 mixins mixin
class BigBox < Box
# 定义类
class Box
# 构造器方法
def initialize(w,h)
@width, @height = w, h
end
# 实例方法
def getArea
@width * @height
end
end
# 定义子类
class BigBox < Box
# 添加一个新的实例方法
def printArea
@area = @width * @height
puts "Big box area is : #@area"
end
end
# 创建对象
box = BigBox.new(6, 8)
# 输出面积
box.printArea()
方法重载
- 想要改变已经在父类中定义的方法的行为 这时可以保持方法名称不变,重载方法的功能即可
allocate 创建对象
- 可以调用 allocate 来创建一个未初始化的对象,这样就不调用对象构造器 initialize 的情况下创建对象,即,使用 new 方法创建对象
方法
- 总是以 小写字母 开头
如果以大写字母作为方法名的开头,Ruby 可能会把它当作常量,从而导致不正确地解析调用
函数调用: 函数如无需传参, 可以不使用括号
> h # h()
方法返回值:
- 默认返回最后一个表达式的值
- 使用 return 语句显示返回
- 显示返回一个或多个值
return 1,2,3
- 显示返回一个或多个值
可变数量的参数
(*names)
方法标记
- 方法定义在类的外部,默认标记为 private
- 方法定义在类中的,默认标记为 public
- 一般情况下,如果想要访问类的方法时,首先必须实例化类。然后,就可以通过对象访问类的任何成员
不用实例化即可访问方法
def ClassName.method_name
- 可直接访问,不用实例化
ClassName.method_name
alias 语句
- 用于为方法或全局变量起别名
alias 别名 方法名
alias 别名 全局变量
undef 语句
- 用于取消方法定义
方法范例
def method_name (var1=value1, var2=value2)
expr..
end
def hello( *names )
print "Hello "
for name in names
print name, " "
end
puts "\nnames length is :#{names.length}"
end
class HelloWorld
def reading_charge
end
def HelloWorld.greet
puts "Hello www.twle.cn"
end
end
HelloWorld.greet
变量常量
- 局部变量
- 实例变量
@
- 未初始化的实例变量的的默认值为 nil
- 类变量
@@
- 不能跨类使用
- 类变量被共享在整个继承链中
- 全局变量
$
- 未初始化的全局变量的默认值为 nil
- 常量
- 常量以大写字母开头
- 常量不能定义在方法内
- 引用一个未初始化的常量会产生错误
- 对已经初始化的常量赋值会产生警告
- 特殊变量
- 有着局部变量的外观,但行为却像常量
- self: 当前方法的接收器对象
- true: 代表 true 的值
- false: 代表 false 的值
- nil: 代表 undefined 的值
- FILE: 当前源文件的名称
- LINE: 当前行在源文件中的编号
- 有着局部变量的外观,但行为却像常量
运算符
算术运算符
- Ruby 支持基本的加减乘除和指数操作
- 加减乘除的操作符是 +-*/
- 指数操作符为 **
puts 1/5 # 0 整数与整数相除 结果返回整数
比较运算符
赋值运算符
并行赋值
- 多个变量可以通过一行的 Ruby 代码进行初始化
a, b, c = 10, 20, 30
- 并行赋值可以用来交换两个变量的值
a, b = b, c
位运算符
逻辑运算符
三元运算符
condition ? expression1 : expression2
序列运算符
- 序列运算符用于创建一系列连续的值
defined? 运算符
defined?
是一个特殊的运算符,以方法调用的形式来判断传递的表达式是否已定义。- 它返回表达式的描述字符串,如果表达式未定义则返回 nil
3.2.2 :001 > var1 = 11
=> 11
3.2.2 :002 > defined? var1
=> "local-variable"
3.2.2 :003 > defined? var2
=> nil
3.2.2 :004 >
> defined? puts # puts 是一个方法
=> "method"
点运算符 "." 和双冒号运算符 "::"
- 点号(.)运算符用来访问类或者模块或实例的方法
- 双冒号(::)运算符用来访问类或模块的常量
运算符优先级
条件语句
if
age = 16
puts("age = #{age}")
if age > 18
puts "青春年少奋斗期"
elsif age <= 18 and age > 0
puts "花样年华一样的年纪"
else
puts "age 的值有错误"
end
if 修饰符
- if 修饰符表示如果 conditiona 为真,则执行 code
age = 16
print "age = #{age}\n" if age > 14
unless
- unless 语句和 if 语句作用相反
- 如果 conditional 为假,则执行 statement1
- 如果 conditional 为真,则执行 else 子句中指定的 statement2
- else 语句是可选的。
unless conditional [then]
statement1
[else
statement2 ]
end
unless 修饰符
- 如果 conditional 为假,则执行 code
age = 16
puts("age = #{age} ")
puts("#{age} 岁是花样年华一样的年纪") unless age > 18
case
- case 语句先对 expression1 进行匹配判断,然后根据匹配结果进行分支选择。
- case 语句使用 === 运算符比较 when 指定的 expression ,若一致的话就执行 statement1
- then 关键字通常可以省略
- 当 case 的 "表达式" 部分被省略时,将计算第一个when条件部分为真的表达式
case expression1
[when expression2 [, expression3 ...] [then]
statmente1 ]...
[else
statement2 ]
end
# ---------
$age = 5
puts "age = #$age"
case $age
when 0 .. 2
puts "婴儿"
when 3 .. 6
puts "小孩"
when 7 .. 12
puts "child"
when 13 .. 18
puts "少年"
else
puts "其他年龄段的"
end
# ---------
a = false
b = true
c = false
case
when a then puts 'a is true'
when b then puts 'b is true'
when c then puts 'c is true'
end
循环语句
while 语句
while conditional [do]
code1
end
或
while conditional [:]
code
end
# 语法中 do 或 : 可以省略不写
i = 0
while i < 5 do puts("在 while 循环语句中 i = #{i}" ); i +=1; end
j = 0
while j < 5
puts("在 while 循环语句中 j = #{j}" )
j +=1
end
# 若要在一行内写出 while 式,则必须以 do 或 : 隔开条件式或程式区块
while 修饰符
- 当 conditional 为真时,执行 statement
- 如果 while 修饰符跟在一个没有 rescue 或 ensure 子句的 begin 语句后面, statement 会在 condition 判断之前执行一次。
statement while condition
或
begin
statement
end while condition
until 语句
- 当 conditiona 为假时,执行 statement
- 语法中 do 可以省略不写。但若要在一行内写出 until 式,则必须以 do 隔开条件式或程式区块
until conditiona [do]
statement
end
until 修饰符
- 当 condition 为 false 时,执行 statement
- 如果 until 修饰符跟在一个没有 rescue 或 ensure 子句的 begin 语句后面, statement 会在 condition 判断之前执行一次
statement until condition
或
begin
statement
end until condition
for和each
for variable [, variable ...] in expression [do]
statement
end
for step in 6..10
puts "step = #{step}"
end
(expression).each do |variable[, variable...]| code end
(6..10).each do |step|
puts "step = #{step}"
end
break 语句
- 终止循环
next 语句
- next 语句用于跳到循环的下一个迭代。
redo 语句
- 重新开始循环
retry 语句
1.9 以及之后的版本不支持在循环中使用 retry 语句
- retry 出现在迭代内、块内或者 for 表达式的主体内,则重新开始迭代调用。 迭代的参数会重新评估。
for i in 1..5
retry if some_condition # 重新从 i == 1 开始
end
- retry 出现在 begin 表达式的 rescue 子句中,则从 begin 主体的开头重新开始。
begin
do_something # 抛出的异常
rescue
statement1 # 处理错误
retry # 重新从 begin 开始
end
块(block)
包含在大括号 {} 内
比方法更简单的组合语句的方式
语法格式
block_name {
statement1
statement2
..........
}
yield 语句
- 块可以被 yield 语句来调用
- yield 语句 可以传参数,获取参数
{|a, b| statement}
- 也可直接调用块
- yield 语句 可以传参数,获取参数
- 通常使用 yield 语句从与其具有相同名称的方法调用块
- 方法与块名称相同 如下,hello方法调用 hello块
def hello
puts "在 hello 方法内"
yield 17
puts "你又回到了 hello 方法内"
yield 33
end
hello{ |i| puts "你在块(block #{i}) 内" }
# 结果
在 hello 方法内
你在块(block 17) 内
你又回到了 hello 方法内
你在块(block 33) 内
传递块
- 如果方法的最后一个参数前带有 &,则可以向该方法传递一个块,且这个块可被赋给最后一个参数
- 如果 * 和 & 同时出现在参数列表中,& 应放在后面
def hello(&block)
block.call
end
hello { puts "Hello World!"}
Hello World!
BEGIN 和 END 块
- 每个 Ruby 源文件可以声明当文件被加载时要运行的代码块(BEGIN 块),以及程序完成执行后要运行的代码块(END 块)
- 一个程序可以包含多个 BEGIN 和 END 块。
- BEGIN 块按照它们出现的顺序执行。
- END 块按照它们出现的相反顺序执行。
BEGIN 语句
- BEGIN 语句中的 code 会在程序运行之前被调用
- 多个按顺序执行,从上往下 执行
BEGIN {
code
}
END 语句
- END 语句会在程序运行结束后被调用
- 多个 从下往上 执行
END {
code
}
模块 (Module)
是一种把方法、类和常量组合在一起的方式。
定义了一个命名空间,相当于一个沙盒,在里边的方法和常量不会与其它地方的方法常量冲突
好处
- 模块提供了一个 命名空间 和避免名字冲突
- 模块实现了 mixin 装置
与类相似
- 模块不能实例化
- 模块没有子类
- 模块只能被另一个模块定义
语法格式
- 以大写字母开头
- 定义一个方法时,可以指定在模块名称后跟着一个点号,点号后跟着方法名
module <ModuleName>
statement1
statement2
...........
end
module Hello
PI = 3.141592654
def Hello.sin(x)
# ..
end
def Hello.cos(x)
# ..
end
end
require 语句
- 加载模块
- require filename
- 使用
$LOAD_PATH << '.'
让 Ruby 知道必须在当前目录中搜索被引用的文件。- 如果不想使用
$LOAD_PATH
,那么您可以使用require_relative
来从一个相对目录引用文件
- 如果不想使用
$LOAD_PATH << '.'
require 'quick.rb'
require 'hello'
y = Quick.sin(Trig::PI/4)
wrongdoing = Hello.sin(Moral::VERY_BAD)
include 语句
- 在类中嵌入模块
$LOAD_PATH << '.'
require "week"
class Decade
include Week
def no_of_months
puts Week::FIRST_DAY
end
end
Mixins
- Ruby 不直接支持多重继承,但是 Ruby 的模块(Module)有另一个神奇的功能。
- 它消除了多重继承的需要,提供了一种名为 mixin 的机制
- Ruby 语言没有真正实现多重继承机制,而是采用 mixin 机制作为替代品
将模块 include 到类定义中,模块中的方法就 mix 进了类中
模块 A 由方法 a1 和 a2 组成
模块 B 由方法 b1 和 b2 组成
类 Hello 包含了模块 A 和 B
类 Hello 可以访问所有四个方法,即 a1、a2、b1 和 b2
$LOAD_PATH << '.'
require "a"
require "b"
class Hello
include A
include B
def s1
end
end
# ------------------------------------------
require "hello"
samp= Hello.new
samp.a1
samp.a2
samp.b1
samp.b2
samp.s1
- 数学模块 Math
- sqrt平方根
> a = 3 ** 2
> b = 4 ** 2
> Math.sqrt(a+b)
=> 5.0
日期 & 时间(Date & Time)
- 内建了 Time 类用来处理日期和时间相关的操作
- Time 类是基于操作系统提供的系统日期和时间之上
注意: Time 类可能无法表示 1970 年之前或者 2038 年之后的日期
t1 = Time.new
puts "当前时间 : " + t1.inspect
t2 = Time.now
puts "当前时间 : " + t2.inspect
time = Time.new
puts time.year # => 日期的年份
puts time.zone # => "UTC":时区名称
格式化时间和日期
time = Time.new
puts time.to_s
puts time.strftime("%Y-%m-%d %H:%M:%S")
Time 算术运算
now = Time.now # 当前时间
puts now
past = now - 10 # 10 秒之前。Time - number => Time
puts past
迭代器
each 迭代器
collection.each do |variable|
code
end
collect 迭代器
- collect 方法返回整个集合,不管它是数组或者是哈希
collection = collection.collect
ary = ["Ali","Tencent","Baidu","JD","DiDi"]
b = Array.new
b = ary.collect{ |x|x..x }
puts b
Ali..Ali
Tencent..Tencent
Baidu..Baidu
JD..JD
DiDi..DiDi
- collect 方法不是数组间进行复制的正确方式。 有另一个称为 clone 的方法,用于复制一个数组到另一个数组
a = [1,3,5,7,11]
b = a.collect{|x| 13*x}
puts b