Ruby讲义

Ruby讲义

本讲义整理自el老师的授课.
本讲义适合有Python, javaScript等语言的学习者快速入门Ruby使用.
各种数据结构的各种方法的细枝末节在正文中略去,放在附录中.

Ruby概览

Ruby(红宝石),是松本行弘发明的脚本语言.本文基于Ruby 2.0写作.

学习方法

大概过一遍本文,然后开始学习各种数据结构之方法的详细用法.

基本数据结构:

  • Array(数组): [1, [1, 2, [1, 2, 3]]]
  • Hash(哈希): 等价表示{a: 1, b: 2}, {:a => 1, :b => 2}.

    :a 是Symbol,相当于一种特殊的字符串常量,等价于'a'.to_sym,一般用来做键.
    
  • 字符串: 'abc' "#{a}bc" 是字符串,双引号的可以插值.

    双引号相当于C语言中`printf("%d",a);`往`%d`填数字, 相当于ES6中的模板字符串.
    

基本语法

换行与缩进

美观即可.

空格

空格只要不影响到解释器分词,一般可以任意增减.

注释

单行注释

# 开头直到本行末尾的内容都被当作注释.

多行注释

=begin #A
    #B
    #B
    #B
=end

AB处都被注释了.
有两点需要注意:

=begin=end必须置于行首.
=begin之后必须要至少跟上一个空格.

Block

{}do;end 都是block(代码块)的标记.一定程度上可以交换使用.


Block的参数列表

||即两个竖线包裹.

在代码块的最前部可选写一个参数列表.

这可能是借鉴了lambda(lisp系语言中的)的表记方法.

见下例, 两种等价方法输出数组内所有元素.
使用do;end包裹block.

如果对乍一看有点神奇的传参语法有疑问,请参考本文方法部分.

[1,2,3].each do |i|
    p i
end
[1,2,3].each{|i| p i}

当然,参数列表可以不止一个参数:

{a: 1, b: 2}.each{|k,v| p [k,v] }

逻辑控制:

结尾的end是不能少的.

if a>0
    #block
elsif a<0
    #block
else
    #block
end
while x>0
    #block
end
case x
    when 1
        #block
    when 2
        #block
end

方法

Ruby没有函数,只有方法. 虽然嘴上这么说,但是我们心中仍可以将”函数”和”方法”看成类似的东西.

方法的定义

我们可以这样定义一个方法add.它接受两个参数ab,返回a+b的结果.

def add(a,b)
    a+b
end

在代码执行中没有遇到显式return的情况下,方法将自动返回最后操作的返回值(哪怕是nil).
若实在无值可返回,例如代码一句都没有被执行,则返回nil.

注意: 指示方法定义结束的end是不可省略的,但是return是可以省略的.这意味着你也可以在方法的定义中显式地return.

方法的参数

这一部分难度比较大. 对没有接触过解构赋值解包的学习者来说需要仔细揣摩.


1. 基本的传参语法
def add_up (a,b,c)
    return a+b+c
end
add_up (1,2,3) # => 6

一般情况下, 参数在定义的时候和在调用时传入方法的时候可以选择不被括号包裹.
也就是说,

def add_up a,b,c
    a+b+c
end
add_up 1,2,3 # => 6

也合语法.

下文采用无括号的写法.


2. Hash和数组作为参数进行 "折叠"

方法定义中, *使得参数折叠成为Array, **使键值对参数折叠成Hash.
二者不能混用, 且一个方法的参数定义里面各最多出现一次,否则报错.

def m a, *c
    p [a, c]
end 

m 1, 2, 3

def m a, b, *c, **d
    p [a, b, c, d]
end

m 1, 2, 3, 4, c:5, d:6 # => [1, 2, [3, 4], {:c=>5, :d=>6}]

3. block(代码块)作为参数

Ruby不提倡使用lambda.
我们可以给方法传block(代码块).习惯上block要写在最后面.

def m orz
    orz.call('test')
end
orz = proc{|i| p i}
m orz # => test

在方法中,可以使用&来把调用时跟着的block转为一个proc对象(参考附录).只有proc对象才可以在block中运行.


def m b, &block
    block.call(b)
end

m (2333) {|i| p i} # => 正确: test
m 2333 {|i| p i} # => SyntaxError: unexpected '{', expecting end-of-input
m 2333 do |i| p i end # => 正确: test

Ruby中的类:

(这个部分还尚未整理完毕)

Ruby中,对象就是一切可以存放到变量里的东西.
Ruby里一切都是对象,一切对象都有其所属的class.

1.class # => Fixnum
Fixnum.class # => Class

给Fixnum加(私有)方法:

Fixnum.send(:define_method, :factorial){ self == 1 ? self : self * (self-1).factorial }

查看1所具有的方法.

1.methods
1.methods.grep /factorial/

自己写一个类(基本版):

        Cat = Class.new
        Cat.send(:define_method, :meow){ p 'meow' }
        cat = Cat.new
        cat.meow

加点语法糖:

class Cat
    def initialize name
        @name = name
        p self
    end
    def meow
        p "#{@name} : meow"
    end
end

test = Cat.new('orange')

使用attr_accessor :nameCat.name提供读写:

class Cat
    attr_accessor :name
    def initialize name
        @name = name
    end
end

这里, attr_accessor :name 相当于

def name
  @name
end

def name= value #定义的时候name必须要和=写在一起
  @name = value
end

Ruby中, class的内部变量是没有办法直接访问的.我们只能通过class自带的方法和对象进行交互!比如使用attr_accessor进行标注就是一个办法.

“对象的内部变量就像是对象的知识. 你没有办法剖开他的大脑直接访问知识, 你需要定义方法与其交互获得知识.”

附录

词汇对照表

Array 数组
Hash 哈希
Block 代码块
Class 类

输出方法

p 或者 print

函数式编程:

    each
    reduce

猜你喜欢

转载自blog.csdn.net/lanadeus/article/details/78911500