+和-是操作符吗?
private和protected有什么不同?
super时会出现ArgumentError?
将依次搜索特殊方法、本类中定义的方法和超类(包括Mix-in进来的模块。写成 类名.ancestors。)中定义的方法,并执行所找到的第一个方法。若没有找到方法时,将按照同样的顺序来搜索method_missing。
module Indexed
def [](n)
to_a[n]
end
end
class String
include Indexed
end
p String.ancestors # [String, Indexed, Enumerable, Comparable, Object, Kernel]
p "abcde".gsub!(/./, "\\&\n")[1]
遗憾的是上述代码返回的是10,而并非预期的"b\n"。这是因为系统在String类中搜索[],在遇到Indexed中定义的方法之前就已经完成了匹配,所以如此。若直接在Class String中重定义[]的话,就会如您所愿了。
+和-是操作符吗?+和-等是方法调用,而并非操作符。因此可进行overload(重定义)。
class MyString < String
def +(other)
print super(other)
end
end
但以下内容及其组合(!=、!~)则是控制结构,不能进行重定义。
=, .., ..., !, not, &&, and, |, or, ~, ::
重定义(或者定义)操作符时,应该使用形如+@或-@这样的方法名。
=是访问实例变量的方法,您可以在类定义中使用它来定义方法。另外,+或-等经过适当的定义之后,也可以进行形如+=这样的自赋值运算。
def attribute=(val) @attribute = val end
Ruby中看似函数的部分实际上都是些省略被调(self)的方法而已。例如
def writeln(str)
print(str, "\n")
end
writeln("Hello, World!")
中看似函数的部分实际上是Object类中定义的方法,它会被发送到隐藏的被调self中。因此可以说Ruby是纯粹的面向对象语言。
对内部函数这种方法来说,不管self如何,它们总是返回相同的结果。因此没有必要计较被调的问题,可以将其看作函数。
不能直接使用。若想操作实例变量,必须事先在对象中定义操作实例变量的方法(accessor)。例如
class C
def name
@name
end
def name=(str) # name 后面不能有空格!
@name = str
end
end
c = C.new
c.name = '山田太郎'
p c.name #=> "山田太郎"
另外,您还可以使用Module#attr、attr_reader、
attr_writer、attr_accessor等来完成这种简单的方法定义。例如,您可以这样来重写上面的类定义。
class C attr_accessor :name end
若您不愿定义访问方法,却想使用实例变量时,可以使用Object#instance_eval。
private和protected有什么不同?private意味着只能使用函数形式来调用该方法,而不能使用被调形式。所以,您只能在本类或其子类中调用private方法。
protected也是一样,只能用在本类及其子类中。但是您既可以使用函数形式又可以使用被调形式来调用它。
在封装方法时,该功能是必不可少。
无法让变量变成public类型的变量。在Ruby中访问实例变量时,需要使用访问方法。例如
class Foo
def initialize(str)
@name = str
end
def name
return @name
end
end
但是每次都这么写的话,未免有些繁琐。因此可以使用attr_reader、attr_writer、
attr_accessor等方法来完成这些简单的方法定义。
class Foo
def initialize(str)
@name = str
end
attr_reader :name
# 其效果等同于下面的代码。
# def name
# return @name
# end
end
foo = Foo.new("Tom")
print foo.name, "\n" # Tom
您还可以使用attr_accessor来同时定义写入的方法。
class Foo
def initialize(str)
@name = str
end
attr_accessor :name
# 其效果等同于下面的代码。
# def name
# return @name
# end
# def name=(str)
# @name = str
# end
end
foo = Foo.new("Tom")
foo.name = "Jim"
print foo.name, "\n" # Jim
若只想定义写入方法的话,可以使用attr_writer。
首先 Ruby把那些只能以函数形式(省略被调的形式)来调用的方法叫做private方法。请注意,这里的private定义与C++以及Java中的定义不同。
若将方法设为private类型之后,就不能在其它的对象中调用该方法了。因此,若您只想在本类或其子类中调用某方法时, 就可以把它设为private类型。
您可以这样把方法设为private类型。
class Foo
def test
print "hello\n"
end
private :test
end
foo = Foo.new
foo.test
#=> test.rb:9: private method `test' called for #<Foo:0x400f3eec>(Foo)
您可以使用private_class_method将类方法变为private类型。
class Foo
def Foo.test
print "hello\n"
end
private_class_method :test
end
Foo.test
#=> test.rb:8: private method `test' called for Foo(Class)
同理,您可以使用public、public_class_method将方法设为public类型。
在默认情况下,类中的方法都被定义成public类型(initialize除外),而顶层中的方法会被定义成private类型。
可以。但要注意:即使方法调用中不带参数,也不能省略方法名后的空括号。
super时会出现ArgumentError?在方法定义中调用super时,会把所有参数都传给上层方法,若参数个数不符合其要求,就会引发ArgumentError。因此,若参数个数不合时,应该自己指定参数然后再调用super。
super只能调用上1层的同名方法。若想调用2层以上的同名方法时,需要事先对该上层方法进行alias操作。
可以在方法定义中使用super。进行重定义之前,使用alias就可以保住原来的定义。也可以把它当作Kernel的特殊方法来进行调用。
就是能修改对象内容的方法,常见于字符串、数组或哈希表中。一般是这样的:存在两个同名的方法,一个会拷贝原对象并返回副本;一个会直接修改原对象的内容,并返回修改后的对象。通常后者的方法名后面带有!,它就是破坏性的方法。但是有些不带!的方法也是具有破环性的,如String#concat等等。
若在方法中对实参对象使用了破环性的方法的时候,就会产生副作用。
def foo(str) str.sub!(/foo/, "baz") end obj = "foo" foo(obj) print obj #=> "baz"
此时,参数对象的内容被修改。另一方面,如果在程序中确有必要的话,也会对某对象发送具有副作用的消息,那就另当别论了。
在Ruby中确实只能指定一个方法返回值,但若使用数组的话,就可以返回多个值了。
return 1, 2, 3
上例中,传给return的列表会被当作数组处理。这与下面的代码可谓是异曲同工。
return [1, 2, 3]
另外,若使用多重赋值的话,则可以达到返回多个值的效果。例如
def foo return 20, 4, 17 end a, b, c = foo print "a:", a, "\n" #=> a:20 print "b:", b, "\n" #=> b:4 print "c:", c, "\n" #=> c:17
您也可以这样处理。