赞 | 0 |
VIP | 25 |
好人卡 | 0 |
积分 | 1 |
经验 | 126953 |
最后登录 | 2020-5-5 |
在线时间 | 39 小时 |
Lv1.梦旅人 粉蜘蛛秀秀
- 梦石
- 0
- 星屑
- 76
- 在线时间
- 39 小时
- 注册时间
- 2007-6-4
- 帖子
- 384
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 忧雪の伤 于 2012-1-2 19:08 编辑
秀秀之走火入魔的高级脚本教程
写这个教程的时候自己已经从地狱里走出来了
为什么这么说 首先可以确定这个教程容易走火入魔 哈哈
因为有些东西真的是很难 经过长时间的钻研
和不停的测试 终于把思路理清楚了 所以决定写出来共享
RMXP 出来估计已经有三年多了吧 很多人已经对脚本非常熟悉
并且能开发独立系统 但是并非对脚本(RUBY语言)理解的透彻
有些难以理解的语法知识可能还是盲点 有的时候是不是看别
人的脚本 大致能看懂 就是有一点地方搞不清楚的地方 所以
这个教程就是针对一些难点来讲 并且配合范例 彻底将大家心
头的难点解开
大概这个教程分为11个部分(可能以后还会添加)
I: 变量
II: 一切皆为对象
III: 类,超类,对象,模块
IV: 字符串,符号,范围
V: 方法 , proc
VI: 内部类(模块)扩展
VII: 试着重写内部方法
VIII: 数据结构,存储
IX: 难以理解的内部方法分析
X: 线程
XI: 正则表达式范例式分析
因为是将难点 所以一些基础知识就不讲了 如类怎么定义之类的
这些可以参考 F1
在讲之前还请各位做好思想准备 如基础不扎实 很有可能走入误区
或者看到崩溃也无法理解? 正常 XD.... 因为是很难的东西嘛
我在此之前也是看过很多夏娜的脚本 从中悟出些东西
当你如能顺利的看懂 你的思路应该相当清晰了
可以写出一些出乎意料的脚本(当然教程中 我会写点临时的脚本)
如有点其他语言的基础 可以尝试开发些ruby的引擎 (如夏娜的RGE...= =)
哈哈 好了 那我们正式开始第一章吧
=====================================
I 变量
=====================================
变量似乎没什么好说的 局部变量 全局变量 可能大家非常清楚
我就说类变量(@@开头)和实例变量吧(@开头)
两者区别(一定要记住):
实例变量是对象的独享的变量 当生成了一个类的对象 这个类中的实例变量
则为这个对象独有 RM默认的类 比如 Game_Battler 类中有很多实例变量
@hp,@sp之类的 每个 Game_Battler 对象都会拥有不同的 @hp,@sp值
实例变量相信大多数人都很清楚
类变量是类中的共享的变量 这个类的所有的对象都共享这个类中的类变量
所以类变量的值是唯一的(只有一个内存地址)
区别很明显可以看出来吧
实例变量如果定义类中 那只有类才能访问 方法是无法访问的
[范例1.1]
class Abc
@a = 0
p a
end
显示结果 1
class Abc
@a = 0
def view_var
return @a
end
end
a = Abc.new
p a.view_var
显示结果 nil
由于view_var返回的是在类中定义的实例变量@a,所以方法中返回为nil
当某个对象更改了当前类的类变量的值 那其他对象的访问类变量的值也改变了
具体看个范例
[范例1.2]
class Abc
@@class_var = 0
def change_class_var(value)
@@class_var = value
end
def view_class_var
return @@class_var
end
end
a = Abc.new
p a.view_class_var
b = Abc.new
b.change_class_var(1)
p a.view_class_var
结果:
0
1
可以看到对象b改变了类变量的值
对象a显示当前类变量的值也改变了
所以可以得出一个结论
类变量是类中的全局变量 这样是不是更加容易理解了?
呵呵 别高兴 事实上类变量也是类对象的实例变量
为什么?请看第二章 一切皆为对象
======================================
II 一切皆为对象
======================================
大家知道 123 是一个数字 那它是Fixnum(长整)类的对象
而Fixnum(长整)类的超类(父类)是Integer(整数)类
这些看过F1内部类的朋友 应该比较清楚
首先我们先了解2个方法
一个是Object类的class方法 也就是对象的方法 作用是返回他是什么类的对象
另一个是Class类的superclass方法 也就是类的方法 作用是返回他的超类
如果没有超类 则返回nil对象
先举一些例子
p "123".class 可以看到结果是 String
p 123.class 可以看到结果是 Fixnum
p [123].class 可以看到结果是 Array
p /123/.class 可以看到结果是 Regexp
这些结果是理所当然的 每个对象返回各自的类
我们拿第一个返回的String类来追查下去
p String.superclass
显示结果 Object
暂且知道String类的超类为 Object
p Object.superclass
显示结果为 nil
说明 Object类 没有超类了 直接返回了对象nil
那我们看对象nil属于什么类
p nil.class
显示结果 NilClass
哈 nil对象还有个NilClass
不管他看看NilClass的超类
p NilClass.superclass
显示结果 Object
又是Object 不成循环了?
Object的父类为nil,nil属于NilClass,而NilClass的父类又是Object
这样的话是不是所有的东西(对象和类)最终的父类都是Object呢?
可以在测试一个例子证实下 拿刚开始的 123 来测试
p 123.class 结果为 Fixnum
p Fixnum.superclass 结果为 Integer
p Integer.superclass 结果为 Numeric
p Numeric.superclass 结果为 Object
= = 看来不管什么追踪到最后一定是Object
接着又是 nil,NilClass,Object 循环
说明循环到最后结果 NilClass 的父类也是Object
这可以得出一个经典的结论 "一切皆为对象(Object)"
既然 "一切皆为对象(Object)"
那类也应该是对象 否则就不符合这句话了
如果以上所说的理解了 我们接着进行第二波测试
p Fixnum.class
p Array.class
p Regexp.class
显示结果依次为 Class Class Class
是不是觉得很惊讶 类居然也是对象
天哪还存在一个Class类 这些内部类 在 Class类面前 只是它的一些对象
之前怎么不知道还有这么一个类 那赶快继续追踪下去看看会有什么神奇的发现
p Class.superclass
显示结果为 Module
= = 又冒出来一个 Module类 是 Class的超类
不管他再继续
p Module.superclass
结果 Object
看来没有悬念的,理论还是对的 追踪到底还是Object
那继续我们的一切皆为对象的追踪
在测试下面四个类对象 看看其所属
p Object.class
p NilClass.class
p Class.class
p Module.class
显示结果仍然是四个 Class
看来已经追踪到根了
只能得出一个结论
所有类对象都是 Class 类的对象
综合以上2项测试 可以得出的结论
所有类的超类都是Object 所有类对象都是Class类的对象
记住这两句话 正是一切皆为对象的精华所在
现在是否能解答第一章那个疑问:
事实上类变量也是类对象的实例变量
你明白了吗?
明白了就好 你有能力去看第三章了
因为 第三章非常难 = =
==========================================================
III 类(Class),超类(superclass),对象(Object),模块(Module)
==========================================================
第一节:对象
上一章我们了解了ruby里一切皆为对象
类既是类又是Class类的对象
Object类里面提供了两个函数 object_id 和 __id__
这两个函数的作用是一样的 其作用是返回对象的唯一标示
暂时可以理解为 一个object_id 对应一个内存地址
看一个例子
[范例3.1]
@a = Bitmap.new(1,1)
3.times{p Bitmap.new(1,1).__id__}
3.times{p @a.__id__}
可以看到第1次输出结果 三个object_id均不一样
第二次则完全相同
由此得出的结论 Bitmap.new(1,1) 没有被赋值直接调用
调用一次就分配一次object_id
被赋值给@a后 调用3次@a.object_id 则是一个固定object_id
虽然ruby会对无用对象调用GC回收垃圾
但对对象的引用还是非常重要的 多引用少生成总是好的
由此可以联想到效率问题
可以再举个例子说明问题
p "123".object_id
不管多少次 结果都不一样
每 p "123" 一次 就生成了一个 String 类的对象
ruby中 每个对象在C中都对应一个 (结构体)struct
String类的结构体中
有定义了一个 char *ptr
还有一个 long len
第一个是字符串指针
第二个是字符串长度
ruby中当一个字符串对象生成 C就会定义一个字符串指针
只想字符串存储的地址 开辟一段长度为len的内存空间
用来存放字符串
因为C里面字符串长度直接定义了long型,所以ruby里不用考虑int,long这些了
有兴趣的朋友可以去参考ruby开源部分 这里就不贴出这些源代码了
说完String类 接着
也有两个特殊的类object_id是唯一的
Fixnum 和 Symbol
我们可以证实下
3.times{p 123.__id__}
3.times{p :123.__id__}
object_id是一样的
为什么呢
其实这两个类特殊类无法生成对象的
Fixnum.new
Symbol.new
报错!说没有new方法....
p Fixnum.methods.include?("new")
其本身在C没有结构体,就对应一个值(Value)
具体没有new方法的类
是因为删除了类方法new
class Fixnum
class << self
undef :new
end
end
这是在虚拟类(元类)中删除了类方法new
这段代码可能很多人就会有疑问了
第二节会着重来解释
第二节:类结构
类大家应该最熟悉不过了
可能很多人不知道真实的类结构
第二章我们讲了ruby一切皆为对象
举个简单例子
a = Sprite.new
p a
p出来的结果是
#<Sprite:0x130cf80>
说明对象a属于Sprite类
0x130cf80 则是对象名称地址
再来看
class Sprite
p self
end
结果显示 Sprite 它是一个类 很好理解
class Sprite
def show
p self
end
end
Sprite.new.show
结果是 #<Sprite:0x130cb78>
是一个对象 因为是在对象方法的内部嘛
也很好理解
最后看2个东西
先一下前面一章最后出现的那个东西
class Fixnum
class << self
p self
end
end
显示结果 #<Class:Fixnum>
赫赫 Fixnum是Class类的对象
也就是类都是Class类的对象
具体这些类对象的作用 就是在
class << self
end
这个区域中体现
这个区域就是隐藏在类和对象背后的 类对象的区域
此区域可以把类视为对象来进行操作
被称之为 虚拟类(virtual class)或者元类(Meta Class)
在看一个
a = "123"
class << a
p self
end
结果:
#<Class:#<String:0x130cba8>>
这种表现形式很奇怪吧 是String类的对象属于Class类
也有点违反常理吧
因为一般情况下表现方法是 某对象直接属于某类
如 "123"属于String类
这样表现我们理解为 某对象形成的类
这个
class << a
理解为 对象a形成的类 一般也是对象
我们称之为元对象
那既然是对象形成的类 那这个类中定义的东西
一定属于这个对象 也是这个对象独有的
如果要把它说成类 那他是一个单态类
那到现在为止说了2个东西
元类和元对象
他们是客观存在的
现在我们能把类的真实地结构明朗化了
1.对象空间 某个类的所有对象都可以访问
2.类空间 类被定义的时候就形成的
3.元类空间 隐藏于类空间和对象空间之后的
也是类被定义的时候形成的
4.元对象空间 类的某个对象独有的空间
对元类和元对象操作 就是元编程了
学会元编程是非常有用的
可以构建一些底层的框架 模版
大家一定知道知道
attr_reader
attr_accessor
这两个方法
如在一个类中
attr_accessor :a
那这个类会在其内部动态的定义两个方法
def a
return @a
end
def a=(value)
@a = value
end
虽然不是很庞大 但也算是一个模板
有了简单的 发掘强大的不就是靠大家的想象力了么?
其就是元编程的结果
所以 元编程是非常强大的
大家都知道
类有实例(对象)方法和类方法
实例方法就不用多说了
类方法最典型的就是 new
如果大家以上80%听懂的话
应该能理解
一个类的类方法也是Class类的实例(对象)方法
具体就不解释了 赫赫
说道这里 如果不能理解的朋友也没关系
可以先消化一下 再继续看下去
如果兴趣还比较浓的话
接下来的元编程的应用 一定能吸引你
==============
第三节:元编程
==============
前一章节讲到了类真实的结构 有4个空间
那我们先来证明一下
还记得第一章的范例1.1吗?
class Abc
@a = 0
def view_var
return @a
end
end
a = Abc.new
p a.view_var
@a 定义在类中
所以@a属于类 并不属于对象
所以对象方法中无法访问
除了类中可以访问@a
还有一个地方可以访问
对 那就是类方法
class Abc
@a = 0
p @a
def view_var
@a = 2
return @a
end
def self.show
return @a + 1
end
end
p Abc.show
p Abc.new.view_var
结果显示
0
1
2
类Abc中定义了两个同名的实例变量@a
但是各自属于不同的空间 也不互相冲突
类方法show中可以访问类空间的@a
实例方法view_var可以访问实例空间的@a
那类还有2个空间
元类的空间 和 元对象的空间
我把这个范例扩展下
[范例3.2]
class Abc
# 这里是类空间
@a = 0
p @a
def view_var
# 对象方法内部是对象空间
p @a # 结果为nil 当前空间未定义
@a = 2
p @a # 结果为 2 当前空间定义了
end
def self.show
# 类方法内部也是类空间
p @a + 1 # 结果为1 开始类空间定义了@a = 0
end
class << self
#这里是元类空间
p @a # 结果为nil 当前空间未定义
@a = 3
p @a # 结果为 3 当前空间定义了
end
class << "abc"
#这里是元对象空间
p @a # 结果为nil 当前空间未定义
@a = 4
p @a # 结果为 4 当前空间定义了
end
end
Abc.show
Abc.new.view_var
测试下来 是否证实了类有4个空间?
答案肯定的 它们相互之间是独立的
每个空间的实例变量@a 作用域只在当前空间
那类变量(@@开头)我们在第一章说过 是类中的全局变量
那类中的4个空间都能访问到它 这里就不再举例了
我们平时做游戏的时候可能都只是在对象空间中操作
类空间也很少用到
最典型的在类空间中用到的就是
attr_accessor(*arg)
这类类函数了
这些概念清楚了 我们终于可以开始写一些应用了
还是看范例
[范例3.3-类方法的定义]
class Abc
def self.show
p "abc"
end
end
Abc.show
其实这种定义方法大多数人都知道
self代表Abc类本身
self.show表示定义类Abc的方法show
也就是Abc的类方法show
把def self.show 替换成
def Abc.shwo 当然也是成立的
还有一种定义类方法的方法
是在自身的元类中定义
class Abc
class << self
def show
p "abc"
end
end
end
Abc.show
可能有些人已经知道是为什么了
元类是把类当作Class类的对象
那在Class类中 也就直接用
def show来定义类对象Abc的对象方法 show了
当然 替换成 class << Abc 也是可以的
是不是很容易理解了?
[范例3.4-私有化对象方法]
class Abc
def show
p "abc"
end
def pr
show
end
private :show
end
Abc.new.pr
Abc.new.show
第一个结果显示"abc"
对象调用其方法pr,
pr方法中再调用show方法 显示出最终结果
第二个结果就报错了
说被私有化的方法无法访问
大家知道被私有化的方法只能在 方法内部调用
无法被对象直接调用 那很显然这个例子就报错了
那私有化类方法怎么实现的呢?
[范例3.5-私有化类方法]
我们来实现下私有化类方法new
class Abc
class << self
private :new
end
end
Abc.new
报错new方法被私有化了 也正是我们想要的结果
但很容易就实现了
有些已经知道的朋友可能已经不需要解释了
但还是解释下吧 = =
请一定要记住了 以后的范例可能很少解释这个了
在Abc的元类中
Abc被看作Class类的对象 私有化了对象Abc的方法 new
其具体作用体现在
Abc作为类 其类方法new被私有化了
那有些朋友可能有疑问了 既然没有了new方法
怎么创建对象呢?
赫赫 很简单的答案 因为是私有化了类方法new
可以自己定义一个 隐藏的new方法
[范例3.5-隐藏的new方法]
class Abc
class << self
private :new
def hidden_new(*args,&blk)
return new(*args,&blk)
end
end
def show
p "abc"
end
end
a = Abc.hidden_new
a.show
Abc类被生成的时候
在其元类中把类方法new私有化掉
在自定义一个类方法hidden_new 用来返回原来的new方法
赫赫 看起来是不是很巧妙?
之前说到的那个范例是不是也很好理解了?
为什么Fixnum类没有new方法呢?
因为他在Class类内被删除了 而不是被私有化了
class Fixnum
class << self
undef :new
end
end
[范例3.5-attr]
class Abc
attr_accessor :a
end
o = Abc.new
o.a = "123"
p o.a
当然创建一个类可以没有构造函数initialize
可以直接用对象初始化,访问或修改属性
如果attr在元类中 就自动创建了类函数
class Abc
class << self
attr_accessor :a
end
end
Abc.a = 9
p Abc.a
我们应该知道一个类的的对象创建的时候会自动
运行函数initialize
如果没有定义 那自然也就不会运行了
所以initialize不是必须的
反之 我们在创建的时候也可以不掉用构造函数
Class类中还提供了一个函数allocate函数
是用来创建一个空对象 其不掉用构造函数initialize
仅分配对象内存
[范例3.6-创建空对象]
class Abc
def initialize
@a = 1
p @a
end
def show
p "123"
end
end
a = Abc.allocate
结果就显示并没有显示 1
说明没有调用initialize函数
调用对象方法还是一样
a.show
显示结果 "123"
那a.initialize这样可以吗?
测试结果说 initialize是私有化方法
难道就没有办法了吗?
有~用对象的send方法可以访问对象的私有化方法
a.send :initialize
这样就可以了
那有了这方法就算new方法被undef了也不怕了
我们可以用 allocate 方法来创建一个空对象
然后用send来访问构造函数initialize
一样达到了new方法的效果
简单的说
创建一个对象就是
先为对象分配内存 然后再初始化函数
new = allocate + initialize
我们还可以根据不同情况来选择使用构造函数
还可以用对象传递block的方法来初始化实例变量
当然这不属于元编程了
既然谈到了构造函数 就举2个例子吧
可能不是很好的方法 仅锻炼思路
[范例3.7-选择创建构造函数]
class Abc
def initialize(a,b,c,d)
@a,@b,@c,@d = a,b,c,d
end
def self.init
return new(1,2,3,4)
end
def self.init2
return new(:a,:b,:c,:d)
end
def show
p @a,@b,@c,@d
end
end
a = Abc.init
b = Abc.init2
a.show
b.show
[范例3.8-block作为构造函数的参数]
class Abc
attr_accessor :a,:b,:c,:d
def initialize(&blk)
instance_eval &blk
end
end
a = Abc.new do
self.a = 0
self.b = "abc"
self.c = ["abc"]
self.d = /abc/
end
p a
[范例3.9-元对象的单态方法]
a = "123"
class << a
def times(n)
p self * n
end
end
a.times(3)
结果是 "123123123"
当然times是单态方法
只属于对象a的方法
[范例3.10-元对象的类方法别名]
a = "abc"
class << a
p self.methods
alias_method(:o_id,:object_id)
end
p a.object_id
p a.o_id
这样直接把object_id方法别名了
并且成为对象a的单态方法
[范例3.10-形成一个单态类]
class Abc
@ori_new = new
class << self
private :new
def singl_new
return @ori_new
end
end
end
先创建一个new的引用@ori_new
然后再其元类中私有化new方法
重新定义一个类方法 singl_new
用来返回一个引用@ori_new
这样创建的类就是一个单态类了
好了通过这些例子大家对元类 元对象
应该有比较深刻地了解了 更多的功能
留给着大家去发掘
====================================
第四节: 模块
====================================
模块就比较简单了
结构没有类那么复杂
因为Module类是Class类的父类
并没有Class类可以创建对象的功能
所以我们认为它是静态的
或者认为它本身就是一个单态类
这也是它的一个特殊性
因为这个特殊性我们可以把它作为一个容器
或者一个封包 用来与类之间的通信
inlcude 方法 就是将模块混入类中
类可以调用模块的方法
这叫做模块的混入技术(Mixin) 相信很多人都知道
我们这里主要讨论一下模块的特殊性
在此之前我们先解答一个范例
[范例3.11]
module Graphics
def self.transition(*args)
end
end
class << Graphics
def.transition(*args)
end
end
第一种重写模块方法 大家应该熟悉
必须方法名前+self
第二种 用我们之前学到东西来分析下
还记得任何类都是Class类的对象么?
赫赫,Module类也不例外 那...
class << Graphics
被称为Graphics的元类
可以解释为
Graphics作为Class类对象
来定义对象方法transition
所以不需要 +self 了
那再看一个范例来证实下
[范例3.12]
module Abc
class << self
def update
p "abc"
end
end
end
class << Abc
alias ori_update update
def update
ori_update
p "def"
end
end
Abc.update
结果显示
"abc"
"def"
看来是这么回事
元类中 定义类方法的别名 也是用alias
如果模块中定义模块方法的别名就不太一样
我们先看如果创建一个模块方法
[范例3.13]
module Abc
def self.show
p "123"
end
end
ori = Abc.methods :show
ori.call
我们把模块方法保存在变量ori里面
成为了一个对象方法
看上去有点像单态方法
但却完全不一样 因为这个对象只是保存了一个方法
属于Method类的对象
所以并不是ori.show就可以执行
那Method类中提供了一个 方法 call
所以需要调用的时候用call方法来调用
同样可以保存对象方法
[范例3.14]
class Abc
def show
p "123"
end
end
a = Abc.new
b = a.method :show
b.call
只要记住 创建Method对象的方法
对象.method :对象方法
如果对象是类的话 比如上面那个例子Abc
那后面的方法就是类方法(类作为对象)
对Method方法有了了解 就很容易想到别名了
还记得now_loading中的这句吗?
原帖: http://rpg.blue/viewthread.php?tid=104649
module Graphics
@@ori = method("transition")
def self.transition(*args)
StartNowLondingTr.stop
@@ori.call(*args)
end
end
记得菜刀兄有过疑问
现在就很好解释了
用类变量@@ori生成一个Method对象
其作用保存了原来的方法 transition
然后重写方法 transition
方法中用 @@ori.call(*args) 把原来的方法
调用回来
然后加入定义其他的东西
感觉是不是跟 alias很像?呵呵
Method类还有一个方法 ality 是用来返回方法参数的个数
如果方法参数为不定参数形势(*args)
返回值为-1
具体作用在元编程里会很常用
记得这句经典的报错吗?
wrong number of arguments(x for x)
表示参数不正确 后面的 x for x
如果 0 for 1
表示 原来方法有1各参数 调用的时候参数为0
这就是一个很经典的元编程
监测方法调用时候的参数
如定义的时候为不定参数则 不检查调用时候的参数
如不是不定参数
调用时候的参数个数和定义的时候数量如果不正确
就调用error程序
模块还有一个特殊性 就是封装
把一些方法 常量封装起来 可以和类进行通信
最常用的方法就是
include 和 extend
[范例3.15]
module A
def show
p "123"
end
end
class Abc
include A
end
Abc.new.show
结果
"123"
这种方法大家都知道
把模块方法引入类中成为对象方法
module A
def show
p "123"
end
end
class Abc
extend A
end
Abc.show
extend则是把模块方法变为类方法
extend还有一种功能就是把
模块方法成为某个对象得单态方法
我们把对象作为单态类来把模块方法
变为单态类的类方法
[范例3.16]
module A
def show
p "123"
end
end
class Abc
end
a = Abc.new
a.extend(A)
a.show
b = Abc.new
b.show
显然 b.shwo 就报错了
对象b没有方法show
最后再说一个经常看到的模块函数
module_function
大家直到 模块中的实例函数
因为模块没有对象的概念 就变成私有的了
要在外部访问这些函数必须让其成为模块函数(类函数)
一种方法就是函数名前加上self
另一种方法就是使用模块函数 module_function
使那些私有的函数变成模块函数
[范例3.17]
module Abc
def pr
p "pr"
end
def pr2
p "pr2"
end
def self.show
p "show"
end
module_function :pr2
end
Abc.show
显示 "show" 因为show是模块函数 直接可以调用
Abc.pr
报错了 没有模块函数pr 因为pr是模块Abc的私有函数
Abc.pr2
显示 "pr2"
因为 module_function :pr2 把 pr2 变为模块函数
所以可以直接调用
module_function 后面参数可以是多个
如 module_function :a,:b
同时把多个私有函数转为模块函数
这点和 private :a,:b 很像
如果 module_function 后面的参数名不写
则 这行以下的私有函数 全部被转为模块函数
记得之前说的模块函数的别名 用到了Method类的对象吗
那模块中那些私有化的方法别名呢?
其实根类中的实例方法别名差不多的
类的实例方法别名用 alias
模块私有方法别名用 alias_method
[范例3.18]
module Abc
def show
p "123"
end
end
module Abc
alias_method :ori,:show
def show
ori
p "456"
end
end
class A
include Abc
end
A.new.show
结果
"123"
"456"
这章节终于讲完了(第五节是纯范例)
相信大家对类的真实结构 模块的特殊性
模块和类的关系 应该有更深一步的了解了
其实本次教程最难得地方已经讲完了
接下来几章 大家看起来可能就轻松一点了 赫赫
==============================
第五节: 综合应用(不断更新范例)
==============================
[范例5.1 attr的实现]
class Class
def new_attr_accessor(*args)
args.each do |name|
class_eval <<-METHODS
def #{name}
return @#{name}
end
def #{name}=(value)
@#{name} = value
end
METHODS
end
end
end
class Abc
new_attr_accessor :a,:c
end
b = Abc.new
b.a = /123/
p b.a
b.c = Sprite.new
p b.c
==============================================
IV: 字符串,符号,范围
==============================================
创建字符串有很多方法
比如
a = "1"
a = String.new("1")
除了这两种 还有一种方法
a = <<-STR
1
STR
这种定义方法比较特别 被称为集成字符串
在STR和STR之间 不需要加单引号('')和双引号("")
如果加了 这些符号也会被认为是字符串
虽然形式不同但都是String对象
<<-STR 和 STR
分别是字符串开始的标志 和 结尾的标志
-号可以省略
但是结尾标志必须写在行首
赫赫 这和
=begin =end代码段注释差不多
不写在首行就报错了
建议还是加上符号-
接着说符号(Symbol)
一个:开头的为符号
大家知道前面说的两个类是无法生成对象的
一个是Fixnum 另一个是Symbol
这些是都是立即值 即直接返回一个值
符号最常用的地方是用于参数传递
我们经常看到 调用方法的时候用符号传递参数
比如
[范例 4.1]
class Abc
def initialize(a)
case a
when :car
p "123"
when "car"
p "456"
end
end
end
Abc.new(:car)
Abc.new("car")
看上去用符号传递和用字符串传递差不多
但是从效率角度上说 符号肯定比字符串效率高
因为符号是立即值么
学过rails框架的朋友一定知道
rails框架就是用大量的符号传递参数
ruby内部有些方法用符号传递
和用字符串传递都是可以的
如 attr_accessor :a
attr_accessor "a"
字符串和符号也可以互相转换
"abc".to_sym 返回 :abc
:abc.to_s 返回 "abc"
有了这两个方法我们可以
p "abc" + :abc.to_s
结果肯定是 "abcabc"
如果要转为符号还得 "abcabc".to_sym
确实有点麻烦
符号类本身没有定义过计算的方法
如 :abc + :abc
不可能返回 :abcabc
我们可以自己动手写一个符号连接的扩展
[范例 4.2]
class Symbol
def +(sym)
return (self.to_s + sym.to_s).to_sym
end
end
p :abc + :abc
这个扩展很简单而且很实用吧 符号其实就这点作用
最后再说下范围
范围也是一个类 Range
就可以用new来创建
也可以用一个变量来保存这个对象
比如
a = Range.new(1,9,false)
for i in a
p i
end
for i in 1..9
p i
end
p a.to_a
这两种方法是一样的
创建范围对象的时候
第三个参数是确定是不是包含最后一个元素
如果不写 则默认为false,包含最后一个元素
to_a方法 可以将范围对象转换为数组对象
范围还可以用英文字母
也可以反向表示
如 "a".."z" ,"Z".."A", 0..-100
范围也有 include? 方法
用于判断是否在范围内
p ("a".."z").include? "x" 返回true
关于这一章节就说到这里
=====================================
V: 方法 , proc
=====================================
===========
第一节 方法
===========
方法有实例方法和类方法
实例方法定义 def + 方法名
类方法定义 def + self. + 方法名
方法名可以用以下几种符号结为
?
!
=
这几种应该大家都接触过
?号结尾一般用于返回一个是(true)或否(false)的结果
我们自己来写一个判断对象是否为字符串的方法
[范例 5.1]
class Object
def a_string?
return self.kind_of?(String)
end
end
p "123".a_string? 结果 true
p 123.a_string? 结果 false
!号结尾一般用于返回修改过的结果 其本身的引用也会被修改
带一定的危险性 默认有gsub 和 gsub!
我们来看下区别
a = "aaaaa"
p a.gsub(/a/){"b"}
p a
p a.gsub!(/a/){"b"}
p a
=号结尾是为方法预定赋值 方法返回的时候就是这个值
如:
[范例 5.3]
class Abc
def abc=(a)
c = 0
b = 100
return 99
end
end
p Abc.new.abc=("123")
返回结果为 "123"
虽然方法内有 return 99 但是返回的结果却是 "123"
因为调用方法的时候=("123")已经为方法确定了返回的结果
接着说 方法的参数
方法的参数 可以是任意的对象
也可以是一个方法 他会执行一次方法然后把返回值传入参数
如 123,"123","123"[0]="1",Sprite.new
[范例 5.4]
class Abc
def show(a,b)
p a
p b
end
end
Abc.new.show("abc"[1]="x",Sprite.new)
结果显示 "x" 和 一个Sprite对象
这种参数是已经把参数的数量确定了
如不确定参数数量的情况下
我们可以用不定参数(*args)
带*号 表示把参数全部放入数组args中
看范例
[范例 5.4]
class Abc
def show(*args)
p args
end
end
Abc.new.show(1,"abc",/abc/,:x)
Abc.new.show("a","b","c")
结果
[1,"abc",/abc/,:x]
["a","b","c"]
还可以只确定其中几个参数 剩下的为不定参数
如
[范例 5.5]
class Abc
def show(s1,s2,*args)
p s1
p s2
p args
end
end
Abc.new.show(1,"abc",/abc/,:x)
Abc.new.show("a","b")
结果大家测试下应该知道了
我们看第二个结果
如果确定2个参数 还有一个不定参数
那如果只带2各参数 不定参数就是一个空数组[]
如果确定2个 调用的时候只有1个参数
那么还是会发生经典的参数数量不正确的error
最后要说的是数组的元素展开作为参数
[范例 5.6]
class Abc
def show(s1,s2,*args)
p s1
p s2
p args
end
end
a = [1,2,3,4,5]
p Abc.new.show(*a)
结果显示
1
2
[3,4,5]
看来数组的元素全部被作为参数了
这是一种经常用到的方法
===========
第二节 proc
=========== |
评分
-
查看全部评分
|