# 变量
Ruby 中有四种类型的变量,变量的命名方式决定了变量的类型
- 局部变量
 以英文字母或者_开头
 
- 全局变量
 以 $ 符号开头
 
- 实例变量
 以 @ 符号开头
 
- 类变量
 以 @@ 开头
 
除了上述四种类型以外,还有伪变量、预定义变量这两种特殊变量。它们是 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 | 
 # 多重赋值
- 同时对 a,b,c 变量进行赋值
多重赋值|  | irb(main):001:0> a, b, c = 1, 2, 3 | 
|  | => [1, 2, 3] | 
|  |  | 
|  |  | 
|  |  | 
|  | 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] | 
|  |  | 
|  |  | 
|  | irb(main):004:0> m, n = 1, 2, 3 | 
|  | => [1, 2, 3] | 
|  | irb(main):005:0> p [m, n] | 
|  | [1, 2] | 
|  | => [1, 2] | 
 - 变量前加上 *,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] | 
 - 用数组赋值时,左边有多个变量时,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] | 
 - 获取嵌套数组的元素
多重赋值|  | 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 两种情况。
- if 语句
if语句|  | a = 10  | 
|  | b = 20 | 
|  |  | 
|  | if a > b | 
|  |   puts 'a比b大' | 
|  | elsif a < b | 
|  |   puts 'a比b小' | 
|  | else | 
|  |   puts 'a等于b' | 
|  | end | 
 - unless 语句
和 if 语句不同,unless 语句是条件为假时进行处理
unless语句|  | a = 10 | 
|  | b = 20 | 
|  | unless a > b then | 
|  |   puts 'a不比b大' | 
|  | end | 
 - case 语句
case 语句中 when 判断值相等时,实际使用的是 === 运算符。当左边是数值或字符串时 === 和 == 意义相同
case语句|  | 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 | 
 # 循环语句
- times 方法
times方法|  | puts '| --times-- |' | 
|  |  | 
|  | 3.times do |i| | 
|  |   puts "| 第#{i + 1}次循环 |" | 
|  | end | 
 - for 语句
for语句|  | puts '| --loop--- |' | 
|  |  | 
|  | for i in 1..3 | 
|  |   puts "| 第#{i}次循环 |" | 
|  | end | 
 - while 语句
while语句|  | puts '| --while-- |' | 
|  |  | 
|  | i = 5 | 
|  | while i < 8 do | 
|  |   puts "| 当前值: #{i} |" | 
|  |   i += 1 | 
|  | end | 
 - until 语句
until语句|  | puts '| -until- |' | 
|  |  | 
|  | sum = 0 | 
|  | i = 1 | 
|  | until sum >= 5 | 
|  |   puts "| 当前sum: #{sum} |" | 
|  |   sum += i | 
|  |   i += 1 | 
|  | end | 
 - each 方法
each方法|  | names = ["alice", "bob", "cyndi"] | 
|  | names.each do |name| | 
|  |   puts "'name': '#{name}'" | 
|  | end | 
|  |  | 
|  |  | 
|  | names.each { |name| | 
|  |   puts "'name': '#{name}'" | 
|  | } | 
 - 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 | 
|  |  | 
|  |  | 
|  |   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 | 
|  |  | 
|  |  | 
|  |   next 的例子 | 
|  |   [1, "Ruby"] | 
|  |   [3, "Java"] | 
|  | =end | 
 - redo:再次执行一次相同的循环,不会再次进行条件判断
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 | 
|  |  | 
|  |  | 
|  |   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  | 
|  |   puts "num is #{num}" | 
|  |   num *= 2 | 
|  | end | 
 yield 是定义带块方法的关键字。调用方法时通过块传进来的处理会在 yield 定义的地方执行。
如果 yield 部分有参数,会被当作块变量传入块里。块里最后的表达式的值既是块的执行结果,
同时也可以作为 yield 的返回值在块的外部使用。
# 可变参数方法
通过使用 ”* 变量名 “ 的形式来定义可变形参
可变形参会被 R 封装成数组,供方法内部使用
可变形参|  | def foo(*args) | 
|  |   args | 
|  | end | 
|  |  | 
|  | p foo(1, 2, 3)  | 
 # 关键字参数
Ruby 中可以使用关键字参数定义方法的参数列表,以 "参数名:参数值" 的形式传入方法。
这种形式为每个参数都指定了一个默认值,因此可以参略任何一个参数进行调用,由于参数名也传给了方法,
所以参数顺序可以自由更改
方法中使用关键字参数|  |  | 
|  | def person(name: 'alice', age: 10, gender: 'm') | 
|  |   puts "[Person] {name: #{name}, age: #{age}, gender: #{gender}}" | 
|  | end | 
|  |  | 
|  |  | 
|  | person()  | 
|  |  | 
|  | person(gender: 'f', name: 'cyndi', age: 32)  | 
 关键字参数只能出现参数列表的最后,如果有普通参数的话,普通参数要先定义
混用参数形式|  |  | 
|  | 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')  | 
 将参数传递给方法时,可以将数组分解后的元素作为参数传递给方法。
调用方法时使用 "* 数组 " 的形式,这时传递给方法的是数组中各个元素。
需要注意的是:数组元素传入的参数个数以及其他参数个数总和要和方法定义的参数个数一致。
把数组分解为参数进行传递|  | def foo(a, b, c) | 
|  |   a + b +c | 
|  | end | 
|  |  | 
|  | p foo(1, 2, 3)  | 
|  |  | 
|  | args1 = [2, 3] | 
|  | p foo(1, *args1)  | 
|  |  | 
|  | args2 = [1, 2, 3] | 
|  | p foo(*args2)  |