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
A
和B
处都被注释了.
有两点需要注意:
=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
.它接受两个参数a
和b
,返回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 :name
为Cat.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