Ruby学习-基础知识

变量

Ruby中有四种类型的变量,变量的命名方式决定了变量的类型

  1. 局部变量 以英文字母或者_开头

  2. 全局变量 以 $ 符号开头

  3. 实例变量 以 @ 符号开头

  4. 类变量 以 @@ 开头

除了上述四种类型以外,还有伪变量、预定义变量这两种特殊变量。它们是Ruby预先定义好的 代表某特定值的特殊变量。伪变量不能改变其本身的值,对其赋值会产生错误,Ruby中,self、 true、false、nil等都是伪变量。预定义变量全部都是以 $ 开头的变量,$$就是其中一个, 它的值表示当前执行中的Ruby进程ID

常量:以大写英文字母开头,多个单词间使用下划线(_)隔开。比如Ruby的运行版本(RUBY_VERSION)、命令行参数数组(ARGV)等,都是Ruby预先定义好的常量。对已经赋值的常量再进行赋值时,Ruby会做出警告

irb(main):001:0> IS_CONSTANT=1
=> 1
irb(main):002:0> IS_CONSTANT=2
(irb):2: warning: already initialized constant IS_CONSTANT
(irb):1: warning: previous definition of IS_CONSTANT was here
=> 2

多重赋值

  1. 同时对a,b,c变量进行赋值
irb(main):001:0> a, b, c = 1, 2, 3
=> [1, 2, 3]

# 即使=号两边数量不相等也不会报错
# 左边个数较多时,Ruby会自动将nil赋值给未分配的变量
irb(main):002:0> x, y, z = 1, 2
=> [1, 2]
irb(main):003:0> p [x, y, z]
[1, 2, nil]
=> [1, 2, nil]

# 右边个数较多时,Ruby会自动忽略多余的值
irb(main):004:0> m, n = 1, 2, 3
=> [1, 2, 3]
irb(main):005:0> p [m, n]
[1, 2]
=> [1, 2]
  1. 变量前加上*,Ruby会将未分配的值封装成数组赋值给该变量
irb(main):006:0> q, w, *t = 1, 2, 3, 4, 5
=> [1, 2, 3, 4, 5]
irb(main):007:0> p [q, w, t]
[1, 2, [3, 4, 5]]
=> [1, 2, [3, 4, 5]]

irb(main):008:0> d, *e, f = 10, 11, 12, 13, 14, 15
=> [10, 11, 12, 13, 14, 15]
irb(main):009:0> p [d, e, f]
[10, [11, 12, 13, 14], 15]
=> [10, [11, 12, 13, 14], 15]
  1. 用数组赋值时,左边有多个变量时,Ruby会自动获取数组的元素进行多重赋值
irb(main):001:0> arr = [1, 2, 3]
=> [1, 2, 3]
irb(main):002:0> a, b = arr
=> [1, 2, 3]
irb(main):003:0> p [a, b]
[1, 2]
=> [1, 2]
  1. 获取嵌套数组的元素
irb(main):004:0> arr = ["nickname", ["age", 20], ]
=> ["nickname", ["age", 20]]
irb(main):005:0> nickname, age = arr
=> ["nickname", ["age", 20]]
irb(main):006:0> p nickname
"nickname"
=> "nickname"
irb(main):007:0> p age
["age", 20]
=> ["age", 20]

# 使用()包裹变量,可以再进一步将内部数组的元素值取出来
irb(main):008:0> arr = [1, [2, 3], 4,]
=> [1, [2, 3], 4]
irb(main):009:0> a, (b1, b2), c = arr
=> [1, [2, 3], 4]
irb(main):010:0> p b1
2
=> 2
irb(main):011:0> p b2
3
=> 3
irb(main):012:0>

条件语句

在Ruby中,真值可以是除false、nil以外的所有对象,假值只有false、nil两种情况。

条件语句中的 then 可以省略

  1. if语句
a = 10 
b = 20

if a > b
  puts 'a比b大'
elsif a < b
  puts 'a比b小'
else
  puts 'a等于b'
end
  1. unless语句

和if语句不同,unless语句是条件为假时进行处理

a = 10
b = 20
unless a > b then
  puts 'a不比b大'
end
  1. case语句

case语句中when判断值相等时,实际使用的是 === 运算符。当左边是数值或字符串时 === 和 == 意义相同

tags = ['Java', 'Ruby', 'C/C++']
tags.each do |tagename|
  case tagename
  when 'Java' then
    puts 'learning Java'
  when 'Ruby' then
    puts 'learning Ruby'
  else
    puts 'learning other languages'
  end
end

循环语句

  1. times 方法
puts '| --times-- |'
# 1. times 循环
3.times do |i|
  puts "| 第#{i + 1}次循环 |"
end
  1. for 语句
puts '| --loop--- |'
# 2. for 循环
for i in 1..3
  puts "| 第#{i}次循环 |"
end
  1. while 语句
puts '| --while-- |'
# 3. while 循环
i = 5
while i < 8 do
  puts "| 当前值: #{i} |"
  i += 1
end
  1. until 语句

until语句当条件不成立时才进行循环

puts '| -until- |'
# 4. until 语句
sum = 0
i = 1
until sum >= 5
  puts "| 当前sum: #{sum} |"
  sum += i
  i += 1
end
  1. each 方法
names = ["alice", "bob", "cyndi"]
names.each do |name|
  puts "'name': '#{name}'"
end

# 等价写法
names.each { |name|
  puts "'name': '#{name}'"
}
  1. break、next、redo

循环语句,一般配合break、next、redo使用

  • break: 终止程序,退出循环
puts "break的例子"
i = 0
langs = ["Ruby", "Rust", "Java"]
langs.each do |lang|
  i += 1
  if i == langs.size
    break
  end
  p [i, lang]
end

=begin 输出
  break的例子
  [1, "Ruby"]
  [2, "Rust"]
=end
  • next:跳过当前循环,直接进入下一次循环
puts "next例子"
i = 0
langs = ["Ruby", "Rust", "Java"]
langs.each do |lang|
  i += 1
  if i == langs.size - 1
    next
  end
  p [i, lang]
end

=begin 输出
  next的例子
  [1, "Ruby"]
  [3, "Java"]
=end
  • redo:再次执行一次相同的循环,不会再次进行条件判断
puts "redo例子"
i = 0
langs = ["Ruby", "Rust", "Java"]
langs.each do |lang|
  i += 1
  if i == langs.size - 1
    redo
  end
  p [i, lang]
end

=begin 输出
  redo的例子
  [1, "Ruby"]
  [3, "Rust"]
  [4, "Java"]
=end

方法

如果想深入了解Ruby的方法可以参考《Ruby元编程》一书

定义带块的方法

def myloop
  while true
    yield # 执行块
  end
end

num = 1
myloop do
  break if num > 64 # ruby特有的写法,可以将条件判断后置
  puts "num is #{num}"
  num *= 2
end

yield 是定义带块方法的关键字。调用方法时通过块传进来的处理会在 yield 定义的地方执行。 如果 yield 部分有参数,会被当作块变量传入块里。块里最后的表达式的值既是块的执行结果, 同时也可以作为 yield 的返回值在块的外部使用。

可变参数方法

通过使用 ”*变量名“ 的形式来定义可变形参 可变形参会被R封装成数组,供方法内部使用

可变参数在方法的参数列表中只能出现一次

def foo(*args)
  args
end

p foo(1, 2, 3) # 输出 => [1, 2, 3]

关键字参数

Ruby中可以使用关键字参数定义方法的参数列表,以"参数名:参数值"的形式传入方法。 这种形式为每个参数都指定了一个默认值,因此可以参略任何一个参数进行调用,由于参数名也传给了方法, 所以参数顺序可以自由更改

# 使用关键字参数
def person(name: 'alice', age: 10, gender: 'm')
  puts "[Person] {name: #{name}, age: #{age}, gender: #{gender}}"
end

# 1. 省略所有参数
person() #=> [Person] {name: alice, age: 10, gender: m}
# 2. 改变参数传递顺序
person(gender: 'f', name: 'cyndi', age: 32) #=> [Person] {name: cyndi, age: 32, gender: f }

关键字参数只能出现参数列表的最后,如果有普通参数的话,普通参数要先定义

# 下面的方法会报错:Exception::,期望出现:号也就关键字参数的形式
def person2(name: 'alice', age: 10, gender: 'm', other)
  puts "[Person] {name: #{name}, age: #{age}, gender: #{gender}, other: #{other}}"
end

# 下面是正确的使用形式
def person3(other, name: 'alice', age: 10, gender: 'm')
  puts "[Person] {name: #{name}, age: #{age}, gender: #{gender}, other: #{other}}"
end

person3('null') #=> [Person] {name: alice, age: 10, gender: m, other: null}

将参数传递给方法时,可以将数组分解后的元素作为参数传递给方法。 调用方法时使用 "*数组" 的形式,这时传递给方法的是数组中各个元素。 需要注意的是:数组元素传入的参数个数以及其他参数个数总和要和方法定义的参数个数一致。

def foo(a, b, c)
  a + b +c
end

p foo(1, 2, 3) #=> 6

args1 = [2, 3]
p foo(1, *args1) #=> 6

args2 = [1, 2, 3]
p foo(*args2) #=> 6