开篇寄语
先后写了Golang和Kotlin两门编程语言的简明入门教程,期间提到过ruby,它的一些语法也被其他编程语言所借鉴,而此前伯衡君写过一篇如何快速掌握ruby编程语言的方法论,而这篇则是也像之前所写的简明教程,撰写一篇简明教程,结合之间的那篇方法论,相信在一两天掌握ruby并不是难事。
前情提要
内容详情
Ruby 是一种动态的、面向对象的、通用的编程语言,它是全球排名前 10 的编程语言之一,它的大部分增长归功于用 Ruby 编写的软件的流行,尤其是 Ruby on Rails Web 框架。作者Matsumoto曾说过,Ruby 是为程序员的生产力和乐趣而设计的,遵循良好的用户界面设计原则。
在 Ruby 中,一切(甚至是简单的数字)都是对象。
基础概念
- Hello World
puts "Hello World"
以上就是一个最简单的ruby函数,类似于python的print(),javascript的console.log()等等。
- 注释
- 单行注释:以“#”为开头
- 多行注释:以“=begin =end”为区间中填写
举例如下:
#单行注释 =begin 多 行 注 释 =end
- format
- 类似于python的format,或者是javascript的`${}`
val a = "World" val helloWorld = "Hello #{a}" #另外一种说法 "hello, %s. Where is %s?" % ["John", "Mary"]
- 变量
- 变量用于存储数据
变量是值的命名存储位置,之所以称为变量,是因为存储在该位置的信息可以在程序运行时更改,这一点很像python的赋值方法。
a = 1 puts a #输出为1
变量名称可以由字母数字字符和下划线字符 (_) 组成,但不能以大写字母或数字开头。
ruby有类似于Javascript的const声明变量的方法,以大写字母开头的变量称为常量,常量变量的值一旦被赋值就不能改变。
MyNum = 42
- 数据类型
- Ruby中的所有变量都可以是所有数据类型
x = 42 puts x.class #结果为Fixnum x = 1.23 puts x.class #结果为Float x = "123" puts x.class #结果为String x = true puts x.class #结果为trueclass x = false puts x.class #结果为falseclass x = [1,2,3] puts x.class #结果为Array x = {:a=>"1",:b=>"2",:c=>"3"} puts x.class #结果为Hash
- 数学运算
- 包括"+",“-”,“*”,“/”,“%”,“++”,“--”,“+=”,“-=”等等,类似于python,不过在运算时,生成的结果会有所不同,ruby生成的结果都是整数
a = 5/2 puts a #结果为2 a = 5**2 puts a #结果为25
- 一行赋多值
- ruby的变量赋值非常灵活,类似于python,如下所示
a,b,c = 20,30,40 puts b #结果为30 a,b,c = [20,30,40] puts c #结果为40 a,*b,c = [20,30,20,40] p b #结果为[30,20]
- 逻辑运算
- 包括“>”,“<”,“>=”,“<=”,“==”,“!=”,“&&”,“||”,“!”等等,类似于Javascript。
- String
- 字符串可以用单引号或者双引号表示,当单引号时如果出现需要添加符号‘怎么办呢?可以用如下几种方式解决
- 字符串和字符串相加生成新的字符串
- 字符串和数字相乘,则是字符串的重复生成
- String的slice切割则用到后面所学的range
- 使用downcase,将字符串中的字母小写
- 使用upcase,将字符串中的字母大写
- 使用capitalize,将字符串中的字母首字母大写
#将单引号修改为双引号形成字符串 a = "I'm 29 years old." #在单引号前添加\ a = 'I\'m 29 years old.' #字符串和字符串相加 a = "1+1" b = "=2" puts a+b #结果为1+1=2 #字符串和整数相乘 a = "1+1" b = 2 puts a*b #结果为1+11+1 #字符串的slice a = "12345" puts a[1..3] #结果为“234” #字符串小写 a = "I love you" puts a.downcase #结果为“i love you” #字符串大写 a = "i love you" puts a.upcase #结果为“I LOVE YOU” #字符串首字母大写 a = "i love you" puts a.capitalize #结果为“I love you”
- 用户输入
- 可以使用gets函数将值作为用户的输入,获取一行文本,包括末尾的新行。如果不想包含新行,请使用 gets.chomp 方法:举例如下:
puts "Enter your name" name = gets.chomp puts "Welcome, #{name}"
- 数据转换
- 字符串整数转整数:“12345”.to_i
- 字符串浮点数转浮点数:"1.234".to_f
- 其他数据类型转字符串:1.24331121.to_s
控制流程
- if/else
- if 语句允许代码在满足条件时运行,也与python的控制流程类似,但是结尾会有一个end。
if num > 0 puts "Positive" elsif num<0 puts "Negative" else puts "Zero" end
- unless/else
- 可以这样理解就是if/else的对立面,简单来说就是如果不是的话那么就……
- ternary operator
- 也像大多数编程语言是这样这样表示 a ? b : c
puts a = true ? b : c
- case...when
- 相当于Javascript中的Switch
a = 2 case a when 1 puts "One" when 2 puts "Two" when 3 puts "Three" end
- while
- 只要给定的条件为真,while 循环就用于重复一段代码
x = 0 while x < 10 puts x x += 1 end
- until Loops
- 只要给定的条件为假,until 循环就用于重复一段代码
x = 12 while x > 10 puts x x -= 1 end #输出结果为12,11
- break和next
- 类似于Javascript中的break和continue
- range
- Ruby 允许您使用以下简单语法轻松创建值范围,在这一点上和Kotlin和Swift这两门编程语言很类似
- 数字范围,字母范围等等,试举一例
a = (2..5).to_a p a #生成[2,3,4,5] a = (2...5).to_a p a #生成[2,3,4] a = ("a".."c").to_a p a #生成["a","b","c"] a = ("a"..."c").to_a p a #生成["a","b"]
- for循环
- 有点类似于python的for循环,试举例如下:
for i in (2..5) puts i end #生成结果为2,3,4,5
- loop...do另一种for循环,类似于while
x = 0 loop do puts x x += 1 break if x > 10 end
数组
- 基本样式
- ruby的Array数组样式与Javascript和python很像,它的表示如下例所示:
- 每一项的位置也是从零开始
- 数组连接用“+”号连接,用“-”号去除重复元素,用“&”组合成两个数组都有的数组
- 重复数组也可以用“*”号
contacts = ["I", "Love", "You"] puts contacts[-1] //输出为“You” a = [1,2,2,3] b = [2,3,4] p a + b #结果为[1,2,3,2,3,4] p a - b #结果为[1] p a & b #结果为[2,3] p a | b #结果为[1,2,3,4] a = [2]*2 p a #结果为[2,2]
- 从末尾添加元素到数组
- 使用push或者“<<”符号来添加
contacts = ["I", "Love", "You"] p contacts<<"!" #结果为["I", "Love", "You", "!"],等价于contacts.push("!")
- 从头部添加元素到数组
- 使用“unshift”来添加
contacts = ["Love", "You", "!"] p contacts.unshift("I") #结果为["I", "Love", "You", "!"]
- pop:去掉数组最后一个元素
- delete_at:去除数组中特定位置的元素
- shift:去掉数组第一个元素
- insert:在任意位置添加元素
- reverse:将数组反转
contacts = ["Love", "You", "!"] p contacts.reverse #结果为["!", "You", "Love"] #另一种写法是 contacts.reverse! =begin 二者的区别是如果使用不带 (!) 的 reverse 方法并且不将其保存到新变量中,它只会反转一次并保留原始值。 =end
- length/size/count:数组的长度,arr.length或者arr.size或者arr.count,字符串也可以用length得出长度
- sort:数组的排序
- uniq:数组中筛选出只出现一次的元素
- uniq!:参考reverse所讲的带“!”和不带的区别
- min:求出数组中的最小值
- max:求出数组中的最大值
- include?:数组中包含某一项吗,这是一个逻辑判断值,结果为true或者false
- map:类似于Javascript中的map函数,遍历数组中的每一个元素,之后执行一定的命令,试举一例:
a = [1,2,3,4,5] p a.map{|x| x*2} #输出的结果为[2,4,6,8,10]
- select
- 类似于Javascript中的filter函数,筛选符合条件的元素,试举一例:
a = [1,2,3,4,5] p a.select{|x| x>=2} #输出的结果为[2,3,4,5]
- Hash
- 类似于Javascript中的Object,Python的dictionary,但是表示方法略有不同
ages = { "David" => 28, "Amy"=> 19, "Rob" => 42 } puts ages["Amy"] #结果为19 #另一种表示方法 ages = { :David => 28, :Amy => 19, :Rob => 42 } puts ages[:Amy] #结果为19
- length:以整数形式返回哈希的长度,如:ages.length
- values:返回一个包含所有Hash值中key所对应的value的新数组,上例中的整数如42,就是所说的value,如:ages.values
- keys:返回一个包含所有Hash值中的key值,如:ages.keys
- invert:返回一个新的Hash值,这个Hash值是key和value对调
- key(value):返回该value所对应的key值,如ages.key(28)
- delete:按键从散列中删除键值对,如ages.delete(:David)
- each
- 在数组中,可以相当于for循环,试举一例:
arr = [2, 4, 6] arr.each do |x| puts x end #如果是Hash,则是这种表示: sizes = {svga:800, hd:1366, uhd:3840} sizes.each do |key, value| puts "#{key}=>#{value}" end #用.times的方法可以执行N次 99.times do puts "Hi" end
函数
- 在前面的课程中,我们已经看到了一些方法的例子,例如数组的reverse方法。
- 方法是一组执行特定任务的语句,可以定义自己的方法来执行所需的任务,def 关键字用于定义方法。
def welcome puts "Hello" end welcome #以后每次调用welcome就会输出“Hello”——第一次 welcome #以后每次调用welcome就会输出“Hello”——第二次 welcome #以后每次调用welcome就会输出“Hello”——第三次 #有arguments def welcome(name) puts "Hello " + name.to_s end welcome("Zhang") #生成结果就是“Hello Zhang” #给arguments添加默认值 def welcome(name="Zhang") puts "Hello " + name.to_s end welcome() #生成结果就是“Hello Zhang” #给arguments添加多项值 def welcome(name, contry='Singapore') puts "Hello " + name + ", I come from " + contry end welcome("Zhang") #生成结果就是"Hello Zhang, I come from Singapore" #给arguments添加不定多项式 def welcome(*p) puts p end welcome(10, "zhang", 44)
- return(不包含它也是可以的哦,但是如果有return,那么return后面的命令行就不执行了)
- 即在构建的函数中返回参数,试举一例:
def divide(a,b) return a - b end puts divide(4,1)//结果为3
- 全局变量与局部变量
- 简单来说在一个函数内的变量是局部变量,在所有函数外的是全局变量,全局变量前要加“$”,试举一例
$x = 42 def change x = 8 end change puts $x
- 递归
- 创建循环的另一种方法是递归,它涉及调用自身的方法的概念,试举一例,求fibonacci函数:
def fibonacci(n) n <= 1 ? n : fibonacci( n - 1 ) + fibonacci( n - 2 ) end puts fibonacci( 10 ) # => 55
面向对象
- class
- 您可以将类视为对象应该由什么组成以及它应该能够做什么的基本轮廓(例如, Car 类的对象应该具有颜色、品牌和型号,并且能够移动)
- Ruby 中的类总是以关键字 class 开头,后跟类名。名称应始终为首字母大写。您可以使用关键字 end 终止类定义,试举一例:
class Person def initialize puts "Hi there" end end p1 = Person.new p2 = Person.new
- @(类变量)
- 实例变量是类中定义的一种类型变量,类的每个对象都有一个单独的实例变量副本,实例变量在符号(@)之前,后跟变量名称(例如:@name)
class Animal def initialize(age) @age = age end end
- 类的方法论
- 实际生活中生物有各种动作,而这个类也可以设置各种动作
- 也可以创建一个实例方法来从对象外部访问实例变量
- Getter 方法用于访问实例变量。如果我们想改变实例变量的值,我们需要 setter 方法,试举例如下:
class Dog def wang puts "wang!" end end d = Dog.new d.wang #生成结果就是一个“wang!” #从外部访问实例变量 class Person def initialize(name) @name = name end def get_name @name end end p = Person.new("David") puts p.get_name #Setter设置变量 class Person def initialize(name) @name = name end def get_name @name end def set_name=(name) @name = name end end p = Person.new("David") p.set_name = "Bob" puts p.get_name
想象一下有很多实例变量和它们的 setter 和 getter 方法。代码会很长,这时候,有一个attr_accessor,可以解决这个问题,试举例如下:
class Person attr_accessor :name def initialize(name) @name = name end end p = Person.new("David") p.name = "Bob" puts p.name
如果蕴含方法method的,则在方法中使用self来调用:
class Person attr_accessor :name, :age def initialize(name, age) @name = name @age = age end def change(n, a) self.name = n self.age = a end def show_info puts "#{self.name} is #{self.age}" end end p = Person.new("David", 28) p.change("Bob", 42) p.show_info
类方法是我们可以直接在类本身上调用的方法,而无需实例化任何对象,当没有逻辑需要创建类的对象时,这会很有用,例如当一个类用于对相似的方法和功能(如数学运算)进行分组时,试举一例:
class Person def self.info puts "A Person" end end Person.info
- 类变量
- 类的每个对象都可以访问类变量。类变量属于类,而不是对象,可以使用两个@ 符号声明一个类变量,例如@@name,试举一例:
class Person @@count = 0 def initialize @@count += 1 end def self.get_count @@count end end p1 = Person.new p2 = Person.new puts Person.get_count
当您需要有关类的信息而不是单个对象时,通常会使用类变量。
- 类的常量
- 常量变量不会改变它们的值并以大写字母开头,常量的名称通常为大写,如下所示:
class Color RGB = 255 end puts Color::RGB #结果为255
- 类的继承
- 继承是指一个类从另一个类接收或继承属性和行为。继承行为的类称为子类(或派生类),而它继承的类称为超类(或基类)
- 使用“<”来继承
class People def initialize(name, male) @name = name @male = male end def speak puts "Hi" end end class Man < People end a = People.new("Zhang", "man") puts a.speak
也可以在子类中定义方法,试举例如下:
class Animal def initialize(name, color) @name = name @color = color end def speak puts "Hi" end end class Dog < Animal end class Cat < Animal attr_accessor :age def speak puts "Meow" end end c = Cat.new("Lucy", "white") c.age = 2 c.speak
- super
- Ruby 有一个名为 super 的内置方法,用于从超类调用方法,当您在子类的方法中调用 super 时,会从超类中调用同名方法,试举例如下:
//例1 class Animal def speak puts "Hi" end end class Cat < Animal def speak super puts "Meow" end end c = Cat.new c.speak //例2 class Animal def initialize(name) @name = name end end class Cat < Animal def initialize(name, age) super(name) @age = age end def to_s "#{@name} is #{@age} years old." end end c = Cat.new("Bob", 3) puts c
- Operator Overloading
- Ruby 允许重载运算符,以便我们可以执行诸如将两个对象相加之类的操作
class Shape attr_accessor :h, :w def initialize(h, w) self.h = h self.w = w end def +(other) Shape.new(self.h+other.h, self.w+other.w) end end a = Shape.new(7, 4) b = Shape.new(9, 18) c = a+b puts c.h //结果为16 puts c.w //结果为22
文件处理
- ruby的文件处理类似于python的文件处理,可以在本机处理文件
file = File.new("test.txt", "w+") #打开文本文件,模式是书写文本 =begin w+ : 读写,将现有文件截断为零长度覆盖现有数据或创建一个新文件进行读写 w : 只写,将现有文件截断为零长度或创建一个新文件进行写入 r : 只读,从文件开头开始(默认模式) r+ : 读写,从文件开头开始 a : 只写,如果文件存在则附加到文件末尾,否则创建一个新文件用于写入 a+ : 读写,如果文件存在,则从文件末尾追加或读取,否则创建一个新文件进行读写 =end file.puts("some text") #添加新内容到这个文本文件 file.close #将文件关闭
还可以这样书写:
File.open("file.txt", "w+") { |file| file.puts("some text") }
- File.read
- 使用这个函数可以阅读整个文本内容,试举例如下:
f = File.new("test.txt", "w+") f.puts("I have a pen") f.puts("I have a pencil") f.close puts File.read("test.txt")
- File.redlines
- 使用这个函数则可以实现一行一行的看文本内容了,试举例如下:
File.open("test.txt", "a+") { |file| file.puts("I have a pen") file.puts("I have a pencil") } File.readlines("test.txt").each { |line| puts " --- #{line}" }
- File.delete
- 删除文本文件
File.delete("test.txt")
- if
- 判断打开的文本文件是否存在
File.open("test.txt") if File.file?("text.txt")
- .size:获得文本文件的大小
- .zero?:判断该文件存在以及大小为0,如果是则为true,相反则为false
- writable?:判断该文件是否可写
- readable?:判断该文件是否可读
- executable?:判断该文件是否可执行
Others
- require
- 类似于python的import,可以引入一些模块,提升效率,减少输入重复的代码量,试举一例:
require "prime" #引入判断是否为质数的模块 Prime.prime?(2) #=> true Prime.prime?(4) #=> false
- Proc或者说是Lambda
- Ruby 提供了将代码块封装在一个对象中的能力,类似于Javascript的() =>{},arrow function,试举一例:
greet = Proc.new do |x| puts "Welcome #{x}" end greet.call "Zhang" #输出结果为Welcome Zhang #lambda用法 talk = lambda {puts "Hi"} #也可以这样写talk = ->() {puts "Hi"} talk.call
- Time
- ruby的时间处理方式很是简洁
#得到当前时间 t = Time.now puts t.inspect #获得当今时刻的年,月,日 puts t.year puts t.month puts t.day #任意时间设置 t = Time.new(1988, 6, 10) #获得星期几,0是周日 puts t.wday #一年时间中的第几天 puts t.yday
- Math
- ruby已经封装好了不少数学用法,比如pi值,cos()值等等,试举一例:
puts Math::PI #结果为3.141592653589793
- <=>
- 翻译成中文是穿梭仓,蕴含了三种结果“大于”,“小于”,“等于”,试着分解如下:
a <=> b := if a < b then return -1 if a = b then return 0 if a > b then return 1 if a and b are not comparable then return nil #来一个更具体的例子 foo = [4, 5, 6] p foo.sort {|a,b| a <=> b} #结果[4, 5, 6, 11]
当然,这一篇只是一篇简明教程,要想加深学习,可以参看ruby的官网深造。
ArrayArrayArray- 我的微信
- 微信扫一扫加好友
- 我的微信公众号
- 扫描关注公众号