在这里,我在类范围中创建一个局部变量:
imageRender()
即使我没有创建class MyClass
x = 1
puts x
end
的任何实例,也会打印1
。
我想在某种方法中使用MyClass
:
x
而我不能。为什么?我得到该类定义创建一个范围,但为什么它不能在方法中访问?该方法的范围不在类的范围内吗?
我可以想象这与创建一个类有关。由于任何类都是class MyClass
x = 1
def method
puts x
end
end
m = MyClass.new
m.method
的对象,因此Class
的范围可能是某些MyClass
方法的范围,以及Class
方法与该实例的耦合方式他们的范围完全不同。
在我看来,我不能仅使用MyClass
(如C语言)或{}
之类的内容创建范围。我是对的吗?
答案 0 :(得分:4)
方法的范围在类中不。每种方法都有自己的全新范围。
每当您使用class
,module
和def
关键字时,都会创建新的范围。使用括号(如C中所示)不会创建新范围,实际上您不能使用括号任意分组代码行。 Ruby块周围的括号(或do
... end
)创建一个块级范围,其中先前在周围范围内创建的变量可用,但在块范围内创建的变量不会转义之后进入周围范围。
实例方法与其他实例方法共享其实例变量的范围。在类定义范围内定义的实例变量在类级单例方法中可用,但在类的实例方法中不可用。
插图:
class Foo
x = 1 # available only here
@y = 2 # class-wide value
def self.class_x
@x # never set; nil value
end
def self.class_y
@y # class-wide value
end
def initialize(z)
x = 3 # available only here
@z = z # value for this instance only
end
def instance_x
@x # never set; nil
end
def instance_y
@y # never set; nil
end
def instance_z
@z # value for this instance only
end
end
Foo.class_x # => nil
Foo.class_y # => 2
Foo.new(0).instance_x # => nil
Foo.new(0).instance_y # => nil
foo3 = Foo.new(3)
foo4 = Foo.new(4)
foo3.instance_z # => 3
foo4.instance_z # => 4
您可以使用类级别的getter从实例中访问类级实例变量。继续上面的例子:
class Foo
def get_class_y
self.class.class_y
end
end
foo = Foo.new(0)
foo.get_class_y # => 2
Ruby中存在“类变量”的概念,它使用@@
符号。在实践中,这种语言结构几乎从来没有合理的用例。通常,使用类级实例变量可以更好地实现目标,如此处所示。
答案 1 :(得分:2)
在这里,我在类范围中创建一个局部变量:
class MyClass x = 1 puts x end
即使我没有创建
1
的任何实例,也会打印MyClass
。
正确。类定义体在读取时执行。它只是像任何其他代码一样的代码,类定义体没有什么特别之处。
问问自己:attr_reader
/ attr_writer
/ attr_accessor
,alias_method
,public
/ protected
/ {{1}等方法如何?否则呢?哎呀,如果在定义类时没有执行,private
将如何工作呢? (毕竟,def
只是一个表达式,就像任何其他表达式一样!)
这就是为什么你可以做这样的事情:
def
我想在某种方法中使用
class FileReader if operating_system == :windows def blah; end else def blubb; end end end
:x
我无法做到。为什么?我得到该类定义创建一个范围,但为什么它不能在方法中访问?这个方法的范围不在类的范围内吗?
不,不是。 Ruby中有4个范围:脚本范围,模块/类定义范围,方法定义范围和块/ lambda范围。只有block / lambdas嵌套,所有其他的都会创建新的范围。
我可以想象这与创建一个类有关。由于任何类都是
class MyClass x = 1 def method puts x end end m = MyClass.new m.method
的对象,因此Class
的范围可能是某些MyClass
方法的范围,以及Class
方法与该实例的耦合方式他们的范围完全不同。
老实说,我不完全理解你在说什么,但不,类定义范围不是方法定义范围,类定义范围是类定义范围,方法定义范围是方法定义范围。
在我看来,我不能仅使用
MyClass
(如C语言)或{}
之类的内容创建范围。我是对的吗?
就像我上面说的:Ruby中有4个范围。没有什么比C中的块范围更好了。"块&#34的Ruby概念与"块的C概念完全不同。")你能得到的最接近的东西是JavaScript启发的立即调用的lambda-literal,如下所示:
do..end
一般来说,Ruby中没有必要这样做。在精心设计的代码中,方法将非常小,跟踪局部变量及其范围和生命周期确实不是什么大问题。
答案 2 :(得分:1)
所以只创建一个没有任何实例的类会导致一些问题 实际上在运行时执行(甚至分配可能)?那是非常的 不喜欢C ++。 -
查看此代码:
Dog = Class.new do
attr_accessor :name
def initialize(name)
@name = name
end
end
如果您执行该代码,则不会有任何输出,但仍然发生了一些事情。例如,创建了一个名为Dog的全局变量,它具有一个值。这是证据:
Dog = Class.new do
attr_accessor :name
def initialize(name)
@name = name
end
end
dog = Dog.new("Ralph")
puts dog.name
--output:--
Ralph
上面对Dog常量的赋值等同于写:
class Dog
...
...
end
事实上,ruby遍历类定义中的每一行并执行每一行 - 除非代码行在def中。 def已创建,但def中的代码不会执行,直到调用def。
您将在类定义中看到的一个非常常见的行是:
attr_accessor :name
...可以改写为:
attr_accessor(:name)
...这显然是一个方法调用。当您运行包含类定义的文件时,Ruby会执行该行 - 并调用该方法。 attr_accessor
方法然后动态创建并将 getter和setter方法插入到类中。在运行时。是的,这不是C ++的土地 - 欢迎来到NeverNever Land。
我得到了类定义创建了一个范围,但为什么不是 方法可以访问吗?
因为这是Matz决定事情的方式:def
创建一个新的范围,阻止def之外的变量的可见性。但是,有一些方法可以打开范围门,可以这么说:blocks
可以看到在周围范围内定义的变量。查看define_method()
:
class MyClass
x = 1
define_method(:do_stuff) do
puts x
end
end
m = MyClass.new
m.do_stuff
--output:--
1
该块是do...end
之间的所有内容。在ruby中,块是一个闭包,这意味着当创建一个块时,它会捕获周围范围内的变量,并随之携带这些变量,直到执行该块为止。块就像一个匿名函数,它作为参数传递给方法。
请注意,如果您使用Class.new技巧,则可以打开两个范围门:
x = 1
MyClass = Class.new do
define_method(:do_stuff) do
puts x
end
end
m = MyClass.new
m.do_stuff
--output:--
1
通常情况下,ruby允许程序员做任何他们想做的事,规则被诅咒。