ruby 语法

1. Here Document: 多行字符串

print <

2. BEGIN 语句

BEGIN {
  code
}

声明 code 会在程序运行之前被调用。

3. END 语句

END {
  code
}

声明 code 会在程序的结尾被调用。

3. 注释

# 这是注释
=begin
这是
多行
注释
=end

4. #{ expr } 替换任意 Ruby 表达式的值为一个字符串

name="Ruby" 
puts "#{name+",ok"}"
输出结果为:
Ruby,ok

5.数组

数组字面量通过[]中以逗号分隔定义,且支持range定义。

(1)数组通过[]索引访问
(2)通过赋值操作插入、删除、替换元素
(3)通过+,-号进行合并和删除元素,且集合做为新集合出现
(4)通过<<号向原数据追加元素
(5)通过*号重复数组元素
(6)通过|和&符号做并集和交集操作(注意顺序)

6.Ruby 类中的变量

* 局部变量:局部变量是在方法中定义的变量。局部变量在方法外是不可用的。在后续的章节中,您将看到有关方法的更多细节。局部变量以小写字母或 _ 开始。
* 实例变量:实例变量可以跨任何特定的实例或对象中的方法使用。这意味着,实例变量可以从对象到对象的改变。实例变量在变量名之前放置符号(@)。
* 类变量(所有实例对象共用):类变量可以跨不同的对象使用。类变量属于类,且是类的一个属性。类变量在变量名之前放置符号(@@)。
* 全局变量:类变量不能跨类使用。如果您想要有一个可以跨类使用的变量,您需要定义全局变量。全局变量总是以美元符号($)开始。
* 常数(Constant): 大写字母开头

7. 自定义方法创建对象

class Customer
   @@no_of_customers=0
   def initialize(id, name, addr)
      @cust_id=id
      @cust_name=name
      @cust_addr=addr
   end
end
cust1=Customer.new("1", "John", "Wisdom Apartments, Ludhiya")

8.Ruby 类中的成员函数

class Sample
   def function
      statement 1
      statement 2
   end
end
class Sample
   def hello
      puts "Hello Ruby!"
   end
end
# 使用上面的类来创建对象
object = Sample. new
object.hello
9.Ruby 伪变量

它们是特殊的变量,有着局部变量的外观,但行为却像常量。您不能给这些变量赋任何值。

* self: 当前方法的接收器对象。
* true: 代表 true 的值。
* false: 代表 false 的值。
* nil: 代表 undefined 的值。
* __FILE__: 当前源文件的名称。
* __LINE__: 当前行在源文件中的编号。

10.Ruby 比较运算符

<=> :第一个操作数等于第二个操作数则返回 0,如果第一个操作数大于第二个操作数则返回 1,如果第一个操作数小于第二个操作数则返回 -1
.eql?:类型和值都需要相等(1 == 1.0 返回 true,但是 1.eql?(1.0) 返回 false)
equal?:具有相同的对象 id,则返回 true(如果 aObj 是 bObj 的副本,那么 aObj == bObj 返回 true,aObj.equal?bObj 返回 false,但是 aObj.equal?aObj 返回 true。)

11.Ruby 并行赋值

 a, b, c = 10, 20, 30
// 交换两个值
a, b  = b, a 

12. 逻辑运算符

and :&&
or  :||
not :!

13. defined? 运算符

defined? 是一个特殊的运算符,以方法调用的形式来判断传递的表达式是否已定义。它返回表达式的描述字符串,如果表达式未定义则返回 nil。

defined? variable # 如果 variable 已经初始化,则为 True
foo = 42
defined? foo    # => "local-variable"
defined? $_     # => "global-variable"
defined? bar    # => nil(未定义)
defined? method_call # 如果方法已经定义,则为 True

14. .和::运算符

点运算符:调用类或模块中的方法
::(常量解析运算符) :引用类或模块中的常量

MR_COUNT = 0        # 定义在主 Object 类上的常量
module Foo
  MR_COUNT = 0
  ::MR_COUNT = 1    # 设置全局计数为 1
  MR_COUNT = 2      # 设置局部计数为 2
end
puts MR_COUNT       # 这是全局常量
puts Foo::MR_COUNT  # 这是 "Foo" 的局部常量
ruby 语法_第1张图片
DC56746E-33C6-490A-928E-3669FC2CAA7F.png

15. 判断

  1. if else 语句
#!/usr/bin/ruby
# -*- coding: UTF-8 -*-
 
x=1
if x > 2
   puts "x 大于 2"
elsif x <= 2 and x!=0
   puts "x 是 1"
else
   puts "无法得知 x 的值"
end
  1. if 修饰符(表示当 if 右边之条件成立时才执行 if 左边的式子)
$debug=1
print "debug\n" if $debug
  1. unless语句(unless式和 if式作用相反,即如果 conditional 为假,则执行 code。如果 conditional 为真,则执行 else 子句中指定的 code。)
#!/usr/bin/ruby
# -*- coding: UTF-8 -*-
 
x=1
unless x>2
   puts "x 小于 2"
 else
  puts "x 大于 2"
end
  1. unless修饰符(表示当 unless 右边之条件不成立时才执行 if 左边的式子)
$var = false
print "3 -- 这一行输出\n" unless $var
  1. Ruby case 语句
case expr0
when expr1, expr2
   stmt1
when expr3, expr4
   stmt2
else
   stmt3
end

基本上类似于

_tmp = expr0
if expr1 === _tmp || expr2 === _tmp
   stmt1
elsif expr3 === _tmp || expr4 === _tmp
   stmt2
else
   stmt3
end
#!/usr/bin/ruby
# -*- coding: UTF-8 -*-
 
$age =  5
case $age
when 0 .. 2
    puts "婴儿"
when 3 .. 6
    puts "小孩"
when 7 .. 12
    puts "child"
when 13 .. 18
    puts "少年"
else
    puts "其他年龄段的"
end
输出:小孩

当case的"表达式"部分被省略时,将计算第一个when条件部分为真的表达式。

case
when foo then puts 'foo is true'
when bar then puts 'bar is true'
when quu then puts 'quu is true'
end
# 显示 "bar is true"

16. 循环

  1. while 语句(语法中 do 或 : 可以省略不写。但若要在一行内写出 while 式,则必须以 do 或 : 隔开条件式或程式区块)
#!/usr/bin/ruby
# -*- coding: UTF-8 -*-

$i = 0
$num = 5

while $i < $num  do
   puts("在循环语句中 i = #$i" )
   $i +=1
end

while $i >= 0
    puts("在循环语句中 i = #$i")
    $i -=1
end
  1. while 修饰符(当 conditional 为真时,执行 code)
#!/usr/bin/ruby
# -*- coding: UTF-8 -*-

$i = 0
$num = 5
begin
   puts("在循环语句中 i = #$i" )
   $i +=1
end while $i < $num

    
def name(count)
    puts("name is xiaoming #{count}")
    $i -=1
end
name($i) while $i >= 0

结果:
在循环语句中 i = 0
在循环语句中 i = 1
在循环语句中 i = 2
在循环语句中 i = 3
在循环语句中 i = 4
name is xiaoming 5
name is xiaoming 4
name is xiaoming 3
name is xiaoming 2
name is xiaoming 1
name is xiaoming 0
  1. Ruby until 语句 (当 conditional 为假时,执行 code)
与while 语句相反
  1. until 修饰符 (当 conditional 为 false 时,执行 code)
与while修饰词相反
  1. (1)Ruby for in语句
#!/usr/bin/ruby
# -*- coding: UTF-8 -*-
 
for i in 0..5
   puts "局部变量的值为 #{i}"
end
  1. (2) Ruby each do
#!/usr/bin/ruby
# -*- coding: UTF-8 -*-
 
(0..5).each do |i|
   puts "局部变量的值为 #{i}"
end

结果:

局部变量的值为 0
局部变量的值为 1
局部变量的值为 2
局部变量的值为 3
局部变量的值为 4
局部变量的值为 5
  1. 循环内语句:
    break语句:跳出循环
    next语句: continue 进行下次循环
#!/usr/bin/ruby
# -*- coding: UTF-8 -*-
 
for i in 0..5
   if i > 2 then
      break
   end
   puts "局部变量的值为 #{i}"
end
结果:
局部变量的值为 0
局部变量的值为 1
局部变量的值为 2

redo 语句(重新开始最内部循环的该次迭代,不检查循环条件。如果在块内调用,则重新开始 yield 或 call)

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-
 
COUNT = 1
for i in 0..5
   if (i < 2 && COUNT < 5) then
      puts "局部变量的值为 #{i}"
      COUNT += 1
      redo
   end
end
结果:
局部变量的值为 0
局部变量的值为 0
局部变量的值为 0
局部变量的值为 0
retry 语句(1.9以及之后的版本不支持在循环中使用retry)
  • 如果 retry 出现在 begin 表达式的 rescue 子句中,则从 begin 主体的开头重新开始。
begin
   do_something   # 抛出的异常
rescue
   # 处理错误
   retry          # 重新从 begin 开始
end

17. 方法

  1. 方法基本构成
# 声明
def method_name 
   expr..
end
def method_name (var1, var2)
   expr..
end

# 默认值
def method_name (var1=value1, var2=value2)
   expr..
end

# 调用
method_name
method_name 25, 30

# 返回值  (默认)
def test
   i = 100
   j = 10
   k = 0
end

# 返回值  (多个)
def test
   i = 100
   j = 200
   k = 300
return i, j, k
end
var = test
puts var
结果: 
100
200
300

# 可变参数 * 符号
# *在方法定义时,可将多个参数放入一个数组中
def sample (*test)
   puts "参数个数为 #{test.length}"
   for i in 0...test.length
      puts "参数值为 #{test[i]}"
   end
end
sample "Zara", "6", "F"
sample "Mac", "36", "M", "MCA"
# *在方法调用时,可将一个数组拆分成多个参数
data = [1,5,9]
big = max(*data)
# *在方法返回时,可将返回的数组展开給另一个方法调用(带*号的方法调用,别懵)
max(*polar(x,y))

# 哈希作为有名参数(应用场景:当一个方法多个参数,很难记参数顺序,ruby又不支持为参数值指定参数名,哈希对象做为参数可以得到近似的功能)
# 为了更好的支持这个风格,当哈希作为最后一个参数(或者其后只有一个&打头的代码块参数)时候可以省略{}
def sequence(args)
  n = args[:n] || 0
  m = args[:m] || 1
end
sequence(:m=>3, :n=>5)
# 关键字参数的方法定义
# 指定参数的默认值
def area2(x:0, y:0, z:0)
xy = x * y
yz = y * z
zx = z *x
(xy+yz+zx) * 2 
end
# 调用的时候指定参数名
area2(x: 2, y: 3, z: 4)
area2(z: 4, y: 3, x: 2) 
# 可以用 散列作为实参
args = {x: 2, y: 3, z: 4}
area2(args)
  1. 类方法 实例方法 单键方法
# 类方法实际就是一种单键方法
# ruby实现上把Fixnum和symbol的值看作立即值而非对象引用,因此无法定义单键方法,为了维持一致性,numeric对象也不能
# 声明
class Accounts
   def reading_charge
       puts "实例方法"
   end
   def Accounts.return_date
       puts "类方法"
   end
   o = "message"
   def o.printme
      p "单键方法"
   end
end

# 调用
Accounts.return_date
Accounts.new.reading_charge
o.printme
# 结果
类方法
实例方法
单键方法
  1. 方法命名
  • 小写开头下划线连接
  • 方法名可以!?= 结尾
  • ? 结尾一般用在返回一个能回答调用者给出问题的值。eg:empty? black? nonzero?
  • ! 结尾的方法要小心调用:代表此方法是可变的方法,会改变对象的内部状态 eg: 数组的sort!
  • = 结尾的方法代表赋值方法
  • 许多ruby操作符是用定义在类中的方法实现的,所以许多操作符可以用方法重载 eg: + * 甚至[] (仅有的例外一元加和一元减用+@和-@定义)

18. alias 语句 和 undef 语句

  • alias 语句用于为方法或全局变量起别名
  • alias 语句更重要的是为一个存在的方法增加新的功能
alias 方法名 方法名
alias 全局变量 全局变量

# eg:
alias foo bar
alias $MATCH $&
def hello
  p "hello word"
end
alias original_hello hello
def hello
  p "change hello"
  original_hello
  p "add other"
end
  • undef 语句用于取消方法定义
  • undef 不能出现在方法主体内
# 下面的实例取消名为 bar的方法定义
undef bar

19. 块(block) 和 yield 语句

  • 代码块的作用域:块中能访问到方法内的局部变量,块中的局部变量仅存在于块中
  • 块由大量的代码组成。
  • 您需要给块取个名称。
  • 块中的代码总是包含在大括号 {} 或do end内。
  • 块总是从与其具有相同名称的函数调用。这意味着如果您的块名称为 test,那么您要* 使用函数 test 来调用这个块。
  • 您可以使用 yield 语句来调用块。
  1. 第一种方式
# 无参:
def nameSay
    puts "name is "
    yield
end

# 可以用花括号和do end作为代码的分节符
# 惯例:代码块只有一行用{} 多行用do end
# 起始的花括号或do关键字必须和方法调用在同一行
nameSay{ puts "xiaoming" }
结果
name is 
xiaoming

nameSay do
puts "xiaoming"
puts "xiaohong"
end 
结果
name is 
xiaoming
xiaohong

# 参数
def test
   yield 5
   puts "在 test 方法内"
   yield 100
end
test {|i| puts "你在块 #{i} 内"}
结果
你在块 5 内
在 test 方法内
你在块 100 内
  1. 第二种方式
def test(&block)
   block.call 1000
end
test {|i| puts "Hello World!#{i}"}
结果
Hello World!1000
# 代码块默认最后一行最为返回值
# 如果希望代码块有多个返回值,或者结束当前进行下次,请用next 关键字
# 不要用return return关键字会导致包含代码块的那个方法返回
array.collect do |x|
  next 0 if x == nil
  next x, x*x
end
# next上述使用并不多见,常用以下这种
array.collect do |x|
  if x == nil
    0
  else
    [x,x**2]
  end
end
  1. 代码块中声明一个与外部同名的块内局部变量的语法(分号)
# 下面是两个参数和三个块级局部变量的代码块
has.each {|key,value;i,j,k| ...}
  1. 代码块传递实参
# 迭代器在传递实参的时候把全局变量变成了:one和实例变量变成了1
{:one=>1}.each_pair {|$key,@value| ...}
# 代码块多个实参
def two
  yield 1,2,3,4,5,6
end
two{|x| p x}  # => in ruby 1.8 :warns and print   [1,2,3,4,5,6]       
two{|x| p x}  # => in ruby 1.9 :no warns and print     1
two{|*x| p x} # => in everyone version :no warns and print   [1,2,3,4,5,6]
two{|x,| p x} # => in everyone version :no warns and print   1
# yield语句和方法一样允许不带花括号的哈希作为最后一个实参(当yield最后一个实参是哈希的时候可以省略花括号)
def hashiter; yield :a=>1, :b=>2; end
# ruby1.9+ 代码块的最后一个行参可以(和方法一样)具有&前置
printer = lambda {|&b| puts b.call}
printer.call {"hi"}

代码块和方法行参的区别是:代码块参数不允许有默认值

[1,2,3].each {|x,y=10| p x*y} # => syntaxError
# in ruby 1.9 新语法可以有默认值,改写如下
[1,2,3].each &->(x,y=10){p x*y} # => 102030
  1. BEGIN 和 END 块
BEGIN { 
  # BEGIN 代码块
  puts "BEGIN 代码块"
} 
 
END { 
  # END 代码块
  puts "END 代码块"
}
  # MAIN 代码块
puts "MAIN 代码块"

结果
BEGIN 代码块
MAIN 代码块
END 代码块

20. 模块(Module):函数追加,共享函数~

Mixins (Ruby 不直接支持多重继承,这个牛逼了~)
module A
   def a1
   end
   def a2
   end
end
module B
   def b1
   end
   def b2
   end
end
 
class Sample
include A
include B
   def s1
   end
end
 
samp=Sample.new
samp.a1
samp.a2
samp.b1
samp.b2
samp.s1
module Trig
   PI = 3.141592654
   def Trig.sin(x)
   # ..
   end
   def Trig.cos(x)
   # ..
   end
end

module Moral
   VERY_BAD = 0
   BAD = 1
   def Moral.sin(badness)
   # ...
   end
end
require 语句:类似于 C 和 C++ 中的 include 语句以及 Java 中的 import 语句
$LOAD_PATH << '.'

require 'trig.rb'
require 'moral'
 
y = Trig.sin(Trig::PI/4)
wrongdoing = Moral.sin(Moral::VERY_BAD)

注释:
1.  $LOAD_PATH << '.' 让 Ruby 知道必须在当前目录中搜索被引用的文件。如果您不想使用 $LOAD_PATH,那么您可以使用 require_relative 来从一个相对目录引用文件
2. 文件包含相同的函数名称。所以,这会在引用调用程序时导致代码模糊,但是模块避免了这种代码模糊,而且我们可以使用模块的名称调用适当的函数
extent 语句 (类中嵌入模块的类方法)
class  Student
  include B
  extend A
end
include语句(类中嵌入模块的实例方法)
# 下面的模块写在 support.rb 文件中
module Week
   FIRST_DAY = "Sunday"
   def Week.weeks_in_month
      puts "You have four weeks in a month"
   end
   def Week.weeks_in_year
      puts "You have 52 weeks in a year"
   end
end

# include 使用
#!/usr/bin/ruby
$LOAD_PATH << '.'
require "support"

class Decade
include Week
   no_of_yrs=10
   def no_of_months
      puts Week::FIRST_DAY
      number=10*12
      puts number
   end
end
d1=Decade.new
puts Week::FIRST_DAY
Week.weeks_in_month
Week.weeks_in_year
d1.no_of_months
# 结果
Sunday
You have four weeks in a month
You have 52 weeks in a year
Sunday
120

21.语句和控制

  • return: 使外围方法返回至调用者,代码块内无论嵌套多深的代码块,他总使得外围方法返回
  • break: 不会使词法意义上的外围方法返回,break只能出现在循环或者代码块中,break 可以带返回值
  • next: 等价其他语言的continue
  • redo: 重新开始一个循环或者迭代的当前迭代,与next的区别,next将控制权传递给下一循环,redo控制权传递给循环或代码块当前迭代的开头,相当于额外进行了一次本循环
  • retry: redo的加强版~,会使得代码块以及迭代器方法推出然后重新开始迭代,ruby 1.9 已经将其移除了,使用要小心无限循环
  • throw/catch: catch不需要和throw处在一个方法内,throw可以跳出当前的循环和代码块,且可以对外跳出任意级数使其与catch一同定义的代码块退出

22. 异常

# raise函数抛出异常
raise Exception.new('not_found_article') if art.nil?
raise Exception.new('try_to_modify_others_article?') unless art.user_id == User.current.id

异常处理的三个从句:

  • rescue : 处理异常
  • else :在不执行rescue情况下会执行else
  • ensure :无论有无异常都会执行(类似oc中的@finlly)
def method_name(x)
  rescue
      ...
  else
      ...
  ensure
      ...
end
# rescue 处理异常 (本事不是一个语句 而是一个可以附加到其他语言上的从句)
def risky
  begin
    10.times do
        explode
      end
  rescue TypeError
    p $!
  end
  "hello"
end
ruby 语法_第2张图片
rescue
作为语句修饰符 rescue
y = factorial(x) rescue x*2
# 相当于 上述代码好处不需要begin end 关键字
y = begin 
          factorial(x) 
      rescue
          x*2
      end  

23. ruby 线程 纤程 连续体(连续体没研究)

# 最简单的线程使用 Thread
f = "file://name"
Thread.new {File.read(f)}
# 纤程fiber
# resume 调用时将会执行block,直到结束或者遇到Fiber.yield类方法,将控制权交给调用者且保存状态,再次执行resume时将继续上次状态继续运行
# 通过resume和yield方法的实参和返回值可以使得纤程与调用者交换数据
2.3.4 :044 > f = Fiber.new{
2.3.4 :045 >    p "Fiber says Hello"
2.3.4 :046?>   Fiber.yield
2.3.4 :047?>   p "goodbye"
2.3.4 :048?>   }
 => # 
2.3.4 :050 > f.resume
"Fiber says Hello"
 => nil 
2.3.4 :051 > f.resume
"goodbye"
# 纤程的应用实现生成器:每次调用返回斐波那数列的下一个数
2.3.4 :055 >   def feibona(x,y)
2.3.4 :056?>   Fiber.new do
2.3.4 :057 >       x_c = x
2.3.4 :058?>     y_c = y
2.3.4 :059?>     loop do
2.3.4 :060 >         Fiber.yield y_c
2.3.4 :061?>         x_c,y_c = y_c,x_c+y_c
2.3.4 :062?>       end
2.3.4 :063?>     end
2.3.4 :064?>   end
2.3.4 :066 > g = feibona 0,1
 => # 
2.3.4 :067 > 10.times{p g.resume}
# 封装版本的
class FibonaGenerator
  def initialize
    @x,@y = 0,1
    @fiber = Fiber.new do
      loop do
        @x,@y = @y,@x+@y
        fiber.yield @x
      end
    end
  end
def next
  @fiber.resume
end
def rewind
  @x,@y = 0,1
end
end
# 使用
g = FibonaGenerator.new
10.times{print g.next} 
g.rewind # 重置
# 第三方库 fiber:可以实现多个fiber之间传递控制权
# transfer :fiber之间穿梭
# alive:检测一个fiber是否在运行
# current:返回当前掌握控制权的fiber
require 'fiber'
f=g=nil
f = Fiber.new{|x| 
  p "f1 is #{x}"
  x = g.transfer(x+1)
  p "f2 is #{x}"
  x = g.transfer(x+1)
  p "f3 is #{x}"
  x+1
}
g = Fiber.new{|x|
  p "g1 is #{x}"
  x = f.transfer(x+1)
  p "g2 is #{x}"
  x = f.transfer(x+1)
}
p f.transfer(1)
==begin
 f1:1
 g1:2
 f2:3
 g2:4
 f3:5
 6
==end

你可能感兴趣的:(ruby 语法)