ruby语言基础
1.ruby简介
编程界几大魔幻语言,c++
、JavaScript
、ruby
和perl
等,个个都是神奇而强大,好坏不一,魔幻的别称不是没来由。perl
这辈子我是不会碰,c++
和JavaScript
算是一家,学会了一种,另外一种过渡不算困难,c++
是爱好。剩下就是ruby
了,号称是要干死python
,现在看来ruby
其实已经半死不活。
本文就是针对ruby
的,现学现卖,希望能够整理出一份比较容易入门的帖子。本文的角度是,假设已经掌握了一门语言,主要目的是快速掌握ruby
的关键语言特性。因为你我的时间都很宝贵,不需要在语言语法上浪费过多的时间。
1.1.hello world
经典的例子,就是是hello world
,ruby中一行语句就可以完成,和python类似。
# 这是一行,注释方法和python类似
puts 'hello world' # 括号可以省略
# p程序员专用 输出字符串时会带有引号,类似puts
p "hello world"
=begin
这是多行注释
puts有多个参数时,每个输出都会换行
print 只在最后添加换行
p 一般是给编程程序员使用
=end
print 'hello', 'world' # 等价于print('hello', 'world')
puts 'hello', 'world'
ruby
中在<<
之后,您可以指定一个字符串或标识符来终止字符串,且当前行之后直到终止符为止的所有行是字符串的值。
# 很ruby的用法,
print <<E # E要成对出现,也可以是其他单词或者字母
hello world!
hello wrold!
E
# 输出
hello world!
hello wrold!
# 您可以把它们进行堆叠,不过先后顺序是不能乱
print <<"foo", <<"bar"
hello foo.
foo
hello bar.
bar
1.2.ruby之旅
1.2.1.顺序语句
定义变量的语法。
# 定义变量,和python一样
i = 1 # 整数
hi = 0xff # 16进制数
bi = 0b1011 # 二进制数
# 全局变量
$gi = 0
$gs = 'this is global string'
# 局部变量作用域,和python差不多
if true then
if_local_var = 0
end
puts if_local_var # if语句内定义的变量依然可见
ruby
语言是纯面向对象,连标准类型也是对象。
# 字符串
s = 'hello world' # 字符串
ss = "string value is #{i}" # 双引号可以通过变量格式化,有点类似python模板
# 下面字符串定义语法,很ruby
s = %q{hello world} # 同 s = 'hello world'
ss = %Q{string value is #{i}} # 同 ss = "string value is #{i}"
# 多行字符串定义
ss = %Q|first line
"second line"
|
puts ss # 输出多行 ,你可以使用{}、[]、||、<>、??、//、\\、;;等等都可以,不一定是{}
# 空值,nil不代表''
s = ''
if s == nil
puts 's is null'
end
# 浮点数
f = 3.14
puts f.round # 3 四舍五入
puts f.ceil # 4 进位
puts f.to_i # 3 转换整数
其他语句的语法举例:
# 多重赋值
a, b, c = 1,2,3 # 定义变量a、b、c
a, b = b, a # 交换a和b的值
array = [1,3,4] # 定义数组
a, b, c = array # 数组解析到变量中
# 三元运算符?: 语句,和C++语法保持一致
max = (10 > 5) ? 10 : 5
# 常量,全部采用大写,如果改写会发出告警
PI = 3.14
# 基础的表达式 比如+ - * / % **
a = 1 * 2
a += 1 # 等价于a = a + 1
# 范围运算符
puts 1..3.to_a # [1, 2, 3]
puts 1...3.to_a # [1, 2]
# 数组与数组迭代
array = [1, 2, 3, 4]
array.each do |it|
puts it
end
puts it # 注意,it生命周期已结束,it未定义
# 数组长度 length和size都是获取数组长度
nums = Array[1, 2, 3, 4,5]
puts "array size is: #{nums.length} or size: #{nums.size}"
puts "#{nums}"
# hash类型,类似json
hash = {"name" => 'ruby1', "age" => 20}
hash.each do | key, value |
puts "key: #{key}, value: #{value}"
end
hash[:name] = 'ruby2' # 访问name节点,不能使用hash["name"]访问
1.2.2.条件语句
控制语句主要有条件、循环等,好消息ruby
好像没有goto
语句。
# 基本的条件语句:if 表达式用于条件执行。值 false 和 nil 为假,其他值都为真
i = 4
if i > 10 then
puts 'i > 10'
elsif i > 5 then
puts 'i > 5'
else
puts 'i in else'
end
# if修饰符
puts 'pass' if 1 > 0
puts 'not ouput' if 0 > 0 # 条件不成立不会输出
# unless语句,与if相反,unless有存在的价值吗?
x = 1
unless x > 2
puts "x <= 2"
else
puts "x > 2"
end
# unlese修饰符
i = 0
puts 'get unless' unless i > 0
# case,这个确实有点丑
age = 5
case age
when 0 .. 2
puts "baby"
when 3 .. 12
puts "child"
when 13 .. 18
puts "young"
else
puts "adult"
end
# ruby没有with语句,可以自己定义一个
1.2.3.循环语句
循环语句主要有while
、do
、until
、for
、break
、next
、redo
、retry
等。
# while语句与while修饰符
a, b = 1, 10
while a < b do
puts "a is #{a}"
a += 1
end
a, b = 1, 10
begin
puts "a is #{a}"
a += 1
end while a < b
# until语句
a, b = 1, 10
until a >= b do
puts "a is #{a}"
a += 1
end
# until修饰符
a, b = 1, 10
begin
puts "a is #{a}"
a += 1
end until a >= b
# for语句
for i in 0..10
puts "i = #{i}"
end
puts i # i依然有定义,i = 10
#遍历数组
names = ['a', 'b']
for name in names
p name
end
# each
(0..10).each do |ii|
puts "ii = #{ii}"
end
puts ii # 此语句失败
# break
for i in 0..10
if i > 3 then break end
puts "i = #{i}"
end
# next if
for i in 0..10
next if i < 3 # 如果i < 3就继续下次循环
puts "i = #{i}"
end
# 等价于
for i in 0..10
if i < 3 then next end
puts "i = #{i}"
end
# redo语句
for i in 0..10
if i < 3 then
puts "i is #{i}"
redo # 这里会出现死循环
end
end
# retry语句已经废弃
# do语句
3.times do
p 'times1'
end
# 用花括号代替 do end
3.times { p 'times2' }
3.times do |i|
p "#{i + 1}times1"
end
3.times { |i|
p "#{i + 1}times2"
}
name = ['a', 'b']
names.each do |name|
p name
end
1.2.3.异常语句
# 异常基本用法
begin
p ii # ii未定义
rescue NameError
# NameError是指定异常,如何不写,就是捕获所有异常
p 'var ii is undefine'
ensure
p 'must exec' # 无论是否有异常,一定会执行
end
# 主动抛出异常
raise Exception.new('this is exception')
raise RuntimeError.new('this is runtime exception')
# 异常隐藏问题,同大多数语言一致
begin
p ii # ii未定义
rescue Exception => err
p "you are here #{err}" # 会执行到这里
rescue NameError
# 实际抛出NameError,被上面捕获拦截了,因为NameError是Exception的子类
p 'var ii is undefine'
end
1.2.3.函数
函数的基本定义:
# 定义一个方法
def first_method()
puts 'this is first method'
end
# 带参数
def second_method(name, age=100)
puts "name: #{name}, #{age}"
end
second_method('china')
second_method('earth',age=1000)
second_method(age=10000, name='sun') # 这里调用结果不是我们预期的,和python是有区别的
second_method(age:10000, name:'sun') # 这样调用也是不行的
# 括号可以省略
second_method 'china', 100
# 定义时候,也可以不用括号
def third_method name, age
puts "name: #{name}, #{age}"
end
third_method 'sun', 10000
# 返回值 return
def return_one(a)
return a * a
end
def return_two(a)
return a * a, a ** 2
end
return_one(10)
a, b = return_two(10)
# 返回return,可以省略
def return_one(a)
a * a # 这里省略了return,这很ruby
end
return_one(10)
函数的参数可变
# 可变参数函数
def sum(*element)
ret = 0
for i in 0...element.length
ret += i
end
return ret
end
sum(1,2,3,4,5)
关键字参数,类似与python,不过python统一了关键字参数和非关键字参数用法。
def distance(x:0, y:0, z:0)
return x**2 + y **2 + z **2
end
puts distance(z:1, x:2, y:3)
puts distance(1,2,3) # 语法错误
# 可变关键字参数
def distance(x:0, y:0, z:0, **kwags)
a1 = x**2 + y **2 + z **2
for v in kwags.values
a1 += v ** 2
end
return a1
end
puts distance(x:1,y:2,z:3,m:4,n:5)
# 关键字参数和非关键字参数可以混用
def distance(x, y, z, **kwags)
a1 = x**2 + y **2 + z **2
for v in kwags.values
a1 += v ** 2
end
return a1
end
puts distance(1,2,3,m:4,n:5)
puts distance(1,2,3,**{m:4,n:5})
函数的别名,取消函数定义、嵌套函数。
# 方法别名alias
alias mysum sum
mysum(1,2,3,4,5) # 调用新的别名方法
# 去除方法定义, 再调用sum和mysum都会出现方法未定义
undef mysum
# 嵌套函数
def outer_func()
def inner_func()
puts 'this is inner function'
end
inner_func()
puts 'this is outer function'
end
outer_func()
inner_func() # 这里也可以调用内部函数
outer_func.inner_func() # 调用失败
# 取消定义
undef outer_func
inner_func() # 这里依然可以调用
lambda函数定义
# lambda函数
ff = lambda{|a,b| return a * b}
ff.call(10,20) # 这里ff调用需要加上.call
ruby由于函数参数都是动态类型,所以也就没有了函数重载能力。这一点和python比较类似。另外,ruby语言层面没有支持装饰器。
1.2.3.类
用户可以通过类创建自定义类型,关键字class
和大多数语言一样的。我们定义一个类Student,有两个属性name和age,代码如下:
class Student
# attr_accessor标示读写,只读attr_reader、只写attr_writer
attr_accessor :name
attr_accessor :age
# 构造函数 initialize,接受两个参数
def initialize(name, age)
# 实例变量亿@开头
@name=name
@age=age
end
end
s = Student.new('ssss', 100)
puts s.name
s.name = 'ssss2'
puts s.name
s.age = 200
puts s.age
类型定义,共有,私有和保护方法
class MyClass
def private_method()
puts 'private method'
end
def protected_method()
puts 'protected method'
end
def public_method()
puts 'public method'
end
private :private_method
protected :protected_method
end
mc = MyClass.new()
mc.public_method()
# run error
mc.protected_method()
mc.private_method()
类定义静态属性,需要定义相应的方法,外部才能够访问。默认情况下,静态属性是私有的。
class StaticClass
@@s_int = 0
@@s_str = 'hello'
def s_int
@@s_int
end
def s_str
@@s_str
end
def self.s_str
@@s_str
end
# 定义类方法
def StaticClass.static_method()
puts 'this is static method'
end
end
puts StaticClass.new.s_int
puts StaticClass.s_str
puts StaticClass.static_method()
# 静态方法,对象不能调用
puts StaticClass.new.static_method()
类继承
class Base
def show
puts 'show method from base'
end
def message
puts 'message from base'
end
end
class Child < Base
def message
puts 'message from child'
end
end
base = Base.new
child = Child.new
base.message()
base.show()
child.message()
child.show()
# 关于多态,ruby是动态语言,天生就支持类型的多态
调用父类的构造方法
class Base1
def initialize(name, age)
puts "base init: #{name} #{age}"
end
end
class Child1 < Base1
def initialize(name, age, phone)
super(name, age)
puts "child init #{phone}"
end
end
child = Child1.new('haha', 100, '136')