热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ruby丰富多彩的高级功能

这一章节我用了两天,把手头的项目也给放了。终于在今天看完了,但仅限于看完,中间还有很多东东还得需要时间去消化。总结下这一章节中看过的内容,大致的包括:模块的定义与使用、其他文件类的导入、自定

这一章节我用了两天,把手头的项目也给放了。终于在今天看完了,但仅限于看完,中间还有很多东东还得需要时间去消化。总结下这一章节中看过的内容,大致的包括:模块的定义与使用、其他文件类的导入、自定义异常的处理、Proc对象的使用、正则表达式、时间类的使用、线程的定义与使用多线程、垃圾回收机制的介绍。看起来的内容还挺多的,而且都比较重要,所以也不枉用了两天的时间来看,庆幸的是这节的内容之前也有所接触,所以看起来也不会那么的费劲,能够快速的理解

首先一个模块是以前没有见过的,模块使用module来定义,而且不能实例化,如果要用里面定义的实例方法,可以把模块放到一个类里,实例化这个类,然后再使用模块里面的实例方法,如下

module MyModule
  def showModule
    puts "这是定义在module里的实例方法"  
  end
  
  def self.showInfo
    puts "这是定义在module的类方法"
  end
end
#模块不能实例化,所以下面的是不存在的
#mm = MyModule.new
MyModule.showInfo
这是定义在module的类方法
 
 

把模块放到类里面,称之为混含操作(感觉像混蛋操作),这样就要以使用模块里的实例方法了

puts "将模块放入类中,这样就可以调用模块中的实例方法了,称之为混含操作"
class ModuleInclude
  include MyModule
end
mi = ModuleInclude.new
mi.showModule
将模块放入类中,这样就可以调用模块中的实例方法了,称之为混含操作
这是定义在module里的实例方法
模块的另一个比较实用的方法就是实现了相当于命名空间的作用,也就是模块与模块之前是隔开的,不会相互影响

puts "module实现命名空间,同样的方法不会报错"
module FirstModule
  class FirstClass
    def show
      puts "FirstModule里FirstClass的show方法"
    end
  end
end

module SecondModule
  class SecondClass
    def show
      puts "SecondModule里SecondClass的show方法"
    end
  end
end
showMethod = FirstModule::FirstClass.new
showMethod.show
secOndMethod= SecondModule::SecondClass.new
secondMethod.show
module实现命名空间,同样的方法不会报错
FirstModule里FirstClass的show方法
SecondModule里SecondClass的show方法
 可以看到,在模块里有相同的sho方法,但不会报错,就算是相同的类名也不会报错,这个方法虽然在类里也可以实现,但模块应该对系统的开支更小 
 

在一个文件执行时,ruby也提供了类似于前置通知和后置通知的功能,使用BEGIN,END/at_exit。这些比较好理解,只是需要注意的是END的执行顺序要和代码的顺序相反的

puts "程序的执行顺序"
BEGIN{
  puts "程序初始化一"
}
BEGIN{
  puts "程序初始化二"
}
def info
  puts "程序运行,复制文件..."
end
info
at_exit{
  puts "program exit one"
}
at_exit{
  puts "program exit two"
}
END{
  puts "程序正在退出一"
}
END{
  puts "程序正在退出二"
}
程序初始化一
程序初始化二
...
程序正在退出二
程序正在退出一
program exit two
program exit one
可以看到,END和at_exit执行的顺序和代码顺序完全相反,而且不管BEGIN/END出现在文件的什么位置,都会是同样的效果

在实际的开发中,肯定不可能把所有的代码写在一个文件内,这时加载其他文件内的内容就显得非常重要了,加载其他文件有两种方式load/require,load可以加载多次,需要指定文件后缀,但require只能加载一次,否则会返回false,不需要指定文件后缀

puts "使用load加载文件资源"
load "demo/moduleY.rb"
require "#{File.dirname(__FILE__)}/demo/modulea"
mod
加载的moduleY.rb中

module ModuleName
  def show
    puts "a show method in ModuleName"
  end
  
  def self.say
    puts "a static say method in ModuleName"
  end
end
ModuleName.say
加载的modulea.rb中

def mod
  puts "hello, my inviewer!"
end
结果:
使用load加载文件资源
a static say method in ModuleName
hello, my inviewer!
如果只是引入一个module可以用include和extend。这就是上面讲的混含操作,include是指引用地址,extend是引入内容

ruby有一个我暂时认为比较无聊的功能-命名别名

puts "为方法定义别名"
def name
  puts "这是之前的name方法"
end
alias new_name name
def name
  puts "这是重定义name之后"
end
name 
new_name
$old = 3
alias $new $old
puts "命名别名,$old重定义之前",$old,$new
$old = 1
puts "命名别名,$old重定义之后",$old, $new
为方法定义别名
这是重定义name之后
这是之前的name方法
命名别名,$old重定义之前
3
3
命名别名,$old重定义之后
1
1
从上面可以看出来,当定义是不是全局变量的时候相当于把原来的内容放到new_name里面,我能想到的不就是用变量保存内容么?要搞个另外的功能吗?而且全局变量的时候别名和原名只能同时改变,真搞不懂这个的作用是什么

如果需要知道当前的这个变量是什么类型的可以使用defined?来判断,又一个体现动态言语的方法undef出现了,这个可以取消已定义的方法,如果再有调用的就会报错,这让我想到了可以利用这个方法来做黑客的入侵功能,嘿嘿~

class Replay
  def play
    puts "开始播放"
    puts defined? "真的开始了吗 ?"
  end
end
rp = Replay.new
puts defined? rp.play
rp.play
#释放定义后将会出错
#undef play
#puts defined?rp.play
method
开始播放
expression
puts defined?rp.play由于这个play是方法,所以输出的是method。后面的“真的开始了吗?”是一个表达式,所以输出了expression

和代码块差不多,让我感觉比较难的Proc对象,用了我大部分的时间,一看到这个我就不想再继续看下去,但没办法,只能逼着看完

Proc对象一个主要的功能就是把一些重复的东东放在一个块在,又没有作用域的限制,在其他地方都可以调用,估计在以后的开发过程中会大量使用

当一个Proc被new出来的时候,并不会马上执行,只有使用了call方法才会被执行,

puts "Proc对象的使用,使其局部变量对象化的过程"
pr = Proc.new{puts "初始化一个Proc对象"}
pr.call
def call_proc(pr)
  a = "我是在proc对象里的变量"
  puts a
  #调用Proc对象
  pr.call
end
a = "我是在外部声明的变量"
pr = Proc.new{puts a}
pr.call
call_proc(pr)
Proc对象的使用,使其局部变量对象化的过程
初始化一个Proc对象
我是在外部声明的变量
我是在proc对象里的变量
我是在外部声明的变量

调用看起来还是比较简单,而且很好理解,当在一个方法参数里添加&,程序则会把这个形参作为Proc对象来处理

def grab_blc(&blc)
  blc.call
end
grab_blc{puts "这是一个形参的proc对象"}
这是一个形参的proc对象
当需要一个Proc对象时,除了用new来初始化,还能用proc方法来生成

alue = proc do |value|
  puts "使用proc方法创建对象,传递的值是:#{value}"
end
Value.call("使用call传值")
def info
  yield "使用yield代码块传值"
end
info &Value
使用proc方法创建对象,传递的值是:使用call传值
使用proc方法创建对象,传递的值是:使用yield代码块传值
在实际使用中,比如一个实体类会被经常使用到,所以把这个实体类做为一个Proc对象

puts "使用proc来输入实体的属性"
def info(pr)
  pr.call
end
entity = Proc.new{
  @name = "wicky"
  @age = 23
  @gender = "male"
  @hobby = "programming"
  
  puts "name:#{@name}"
  puts "age:#{@age}"
  puts "gender:#{@gender}"
  puts "hobby:#{@hobby}"
}
info (entity)
使用proc来输入实体的属性
name:wicky
age:23
gender:male
hobby:programming
任何一门言语,异常处理机制是不可或缺的,因为程序写的不可能完美,ruby提供的异常处理和其面向对象语言差不多,而且定义的异常也简单的多,包括:RuntimeError/IOError/Errorno::error/NameError/NoMethodError/TypeError/ArgumengError,总共才7个,所以运用起来也方便很多,捕获的方法也很简单,相当于try(){}catcher的,begin/end块来包含可能出现异常的代码,使用rescue来声明捕获的异常,还提供了手动抛出异常的raise和重新运行异常代码块的retry,虽然ruby本身的异常处理机制已经很简单明了,但还是人性化的提供了自定义异常,和自定义异常提示方法。下面是一个异常的模拟

isError = true
begin
  puts "正在请求服务器,请稍后..."
  if isError
    raise "连接超时"
  end
  puts "请求成功"
  
  rescue
    isError = false
    puts "#{$!.to_s},重新请求"
    retry
end
正在请求服务器,请稍后...
连接超时,重新请求
正在请求服务器,请稍后...
请求成功
模拟的是连接服务器的过程,当第一次运行时,isError=true,会进入raise手动抛出异常,并且带有自定义的异常信息,这时程序跳到rescue处理异常,把isError=false模拟连接成功,并且打印出异常信息($!是全局保存异常信息的变量,$@保存全局异常信息的位置等),这时调用了retry重新连接服务器。关于自定义的处理也比较简单,无非就是自己定义一个类,然后继承下Exception就完事了,后面了处理只要把捕获到的异常raise成自己的异常类就行了

编程另外一个非常重要的知识点线程,这是任何程序猿都必须知道的事,ruby的线程操作非常简单,大大简化了线程的操作过程,而且提供了很多有用的库供使用

i = 1
thread = Thread.new do
  10.times { |count|
    puts "当前线程#{count}"
  }
end
thread2 = Thread.start do
  puts "这是线程2"
end
#不加入线程则,无法打印出信息
thread.join
thread2.join
当前线程0
当前线程1
当前线程2
当前线程3
当前线程4
当前线程5
当前线程6
当前线程7
当前线程8
当前线程9
这是线程2
不知道是不是版本的问题,我用的是1.9.3必须得把这个线程join到当前运行的线程中才可以打印信息,但有些版本好像可以不用join,真搞不懂
ruby提供了一个非常好的类来处理著名的售票问题

@num = 200
@mutex = Mutex.new
def ticketSeller(tickets)
  @mutex.lock
  Thread.pass
  if (@num >= tickets)
    @num -= tickets
    puts "您购买#{tickets}已成功"
  else
    puts "出票失败,没足够的票,当前余票#{@num}" 
  end
  @mutex.unlock
end
buyer1 = Thread.new(199){|num| ticketSeller(num)}
buyer2 = Thread.new(2){|num| ticketSeller(num)}
buyer1.join
buyer2.join
您购买199已成功
出票失败,没足够的票,当前余票1
Mutex提供了一个线程锁,能够把当前的这个块锁定,不让其他线程访问,这样就可以保证数据的正确性,直到调用unlock方法,另外线程还提供了pass/sleep/join/wakeup/current等显示/休眠/挂起/唤醒/当前线程方法,如果需要查询当前的线程状态可以用到status。拥有的值有:sleep/run/aborting/false/nil表示休眠、运行、被取消、正常终止、被非正常终止等。另一个比较常用的库SizedQueue也非常有用,能够让线程按顺序执行,而不用担心同步问题

在这节的学习中,是学习ruby为止比较重要而且比较难的部分,写的代码也越来越多,越来越复杂,一些常见的基础知识也基本用到了,接下来就得了解ruby的IO操作为对数据库的操作了,看完这两个比较重要的内容准备着手ROR,毕竟不断的挑战难点才能回首现在,让现在难以理解或使用的知识自动变的简单

KEEPPING UP



推荐阅读
  • 问题描述现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能;在实际开发过程中 ... [详细]
  • 本文详细介绍了如何在 Ubuntu 14.04 系统上搭建仅使用 CPU 的 Caffe 深度学习框架,包括环境准备、依赖安装及编译过程。 ... [详细]
  • 本文详细介绍如何在 Apache 中设置虚拟主机,包括基本配置和高级设置,帮助用户更好地理解和使用虚拟主机功能。 ... [详细]
  • 深入理解Java SE 8新特性:Lambda表达式与函数式编程
    本文作为‘Java SE 8新特性概览’系列的一部分,将详细探讨Lambda表达式。通过多种示例,我们将展示Lambda表达式的不同应用场景,并解释编译器如何处理这些表达式。 ... [详细]
  • 大华股份2013届校园招聘软件算法类试题D卷
    一、填空题(共17题,每题3分,总共51分)1.设有inta5,*b,**c,执行语句c&b,b&a后,**c的值为________答:5 ... [详细]
  • 驱动程序的基本结构1、Windows驱动程序中重要的数据结构1.1、驱动对象(DRIVER_OBJECT)每个驱动程序会有唯一的驱动对象与之对应,并且这个驱动对象是在驱 ... [详细]
  • 我自己做了一个网站图片的抓取,感觉速度有点慢抓取4000张图片可能得用15分钟左右的时间,我百度看用线程可以加快抓取,然后创建了5个线程抓取,但是5个线程是同步执行同样的操作一个图片就 ... [详细]
  • 在运行于MS SQL Server 2005的.NET 2.0 Web应用中,我偶尔会遇到令人头疼的SQL死锁问题。过去,我们主要通过调整查询来解决这些问题,但这既耗时又不可靠。我希望能找到一种确定性的查询模式,确保从设计上彻底避免SQL死锁。 ... [详细]
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • 本文详细介绍如何在SSM(Spring + Spring MVC + MyBatis)框架中实现分页功能。包括分页的基本概念、数据准备、前端分页栏的设计与实现、后端分页逻辑的编写以及最终的测试步骤。 ... [详细]
  • 本文探讨了使用Python实现监控信息收集的方法,涵盖从基础的日志记录到复杂的系统运维解决方案,旨在帮助开发者和运维人员提升工作效率。 ... [详细]
  • 本文探讨了Java中线程的多种终止方式及其状态转换,提供了关于如何安全有效地终止线程的指导。 ... [详细]
  • JUC并发编程——线程的基本方法使用
    目录一、线程名称设置和获取二、线程的sleep()三、线程的interrupt四、join()五、yield()六、wait(),notify(),notifyAll( ... [详细]
  • 本文总结了近年来在实际项目中使用消息中间件的经验和常见问题,旨在为Java初学者和中级开发者提供实用的参考。文章详细介绍了消息中间件在分布式系统中的作用,以及如何通过消息中间件实现高可用性和可扩展性。 ... [详细]
  • 本文详细介绍了Sleep函数的基本概念、使用方法及其背后的实现原理。适合对Sleep函数的使用和实现感兴趣的开发者阅读。通过本文,您将了解如何在不同操作系统中使用Sleep函数,以及其在多线程编程中的重要性。 ... [详细]
author-avatar
啥也不会
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有