Ruby中的“main”是什么?

aemubtdh  于 2023-01-12  发布在  Ruby
关注(0)|答案(6)|浏览(241)

如果以“ruby x.rb“运行此文件:

class X
end
x = X.new

调用“X.new“的东西是什么?
它是一个对象/进程/等等吗?

fsi0uk1n

fsi0uk1n1#

顶级调用方是Object类的对象main。
试试这个ruby程序:

p self
p self.class
uxh89sit

uxh89sit2#

这是X类,你正在调用new方法来创建X类的对象,所以,如果你把这段文字作为脚本运行,Ruby:

  • 创建一个新类X,它是Object的子类,并且自动(作为Object的子类)继承一些方法,new就是其中之一。
  • 设置名称x
  • 调用新类X上的new方法,创建X示例对象;x得到对该对象的引用。
brqmpdu1

brqmpdu13#

是ruby解释器在运行这行代码

x = X.new

与许多脚本语言一样,脚本是从上到下解释的,而不是像大多数编译语言那样具有标准的入口点方法。

afdcj2ne

afdcj2ne4#

正如Charlie Martin所说,X.new是对X类上构造函数的调用,它返回一个类型X的对象,存储在变量x中。
基于你的标题,我认为你需要更多的东西。Ruby不需要main,它按照它看到的顺序执行代码。所以依赖关系必须在调用之前包含在内。
因此,main是在类或模块定义之外编写的任何过程样式代码。

1zmg4dgp

1zmg4dgp5#

main是在其上下文中执行顶层代码的对象。这意味着顶层的self引用main对象:

$ ruby -e 'p self'
main

并且ruby遵循main的方法查找链来确定调用哪个方法:

$ ruby -e 'p singleton_class.ancestors'
[#<Class:#<Object:0x00007f9e9fdee230>>, Object, Kernel, BasicObject]

可能会有更多,但这是你从一开始就得到的。
main本身是Object的示例:

$ ruby -e 'p self.class'
Object

它有一个单例类,该类有2个方法(更准确地说是一个方法和一个别名):

$ ruby -e 'p singleton_class.instance_methods(false)'
[:inspect, :to_s]
$ ruby -e 'p singleton_methods'
[:inspect, :to_s]

它在这里定义。
正如您所看到的,它的to_s方法返回"main"(覆盖Object的行为),这是您执行p self时得到的结果。
你可以认为你执行的代码被放进了main的方法中,然后这个方法被调用。

main = Object.new
class Object
  def main.go
    <your code here>
  end
end
main.go

这是一个粗略的想法,让我分几步来说明它的合理性。
在Ruby中,实际上可以嵌套方法,但是每次调用外部方法时,内部方法都会被定义/重定义,更重要的是,它被定义为嵌套类的一个示例方法:

class A
  def m
    def m2; end
  end
end
A.new.m
p A.instance_methods(false)  # [:m2, :m]

同样的情况也发生在这里,但是这里的封闭类是A的单例类:

class A
  class << self
    def m
      def m2; end
    end
  end
end
A.m
p A.singleton_class.instance_methods(false)  # [:m2, :m]

如果我们使用def self.<name>表示法呢?

class A
  def self.m
    def m2; end
  end
end
A.m
p A.singleton_class.instance_methods(false)  # [:m]
p A.instance_methods(false)                  # [:m2]

因此,self.只影响mm2成为A的示例方法。
实际上,除了self之外,还可以有一些随机对象:

o = Object.new
A = Class.new do
  def o.m
    def m2; end
  end
end
o.m
p o.singleton_class.instance_methods(false)  # [:m]
p A.instance_methods(false)                  # [:m2]

我必须使用Class.new,因为使用classo在类定义中不可见。
其实我没有

class A
  o = Object.new
  def o.m
    def m2; end
  end
  o.m
  p o.singleton_class.instance_methods(false)  # [:m]
  p A.instance_methods(false)                  # [:m2]
end

但我们先忽略这一分支。
做了一些改动,你会得到这个:

main = Object.new
Object.class_eval do
  def main.go
    @a = 1
    def m2
      puts @a
    end
    m2                            # 1
  end
end
main.go
p Object.instance_methods(false)  # [:m2]
p main.instance_variables         # [:@a]

我不得不使用class_eval,这样它就不会抱怨我试图重新定义Object常量。
您还可以添加:

def main.to_s
  "main"
end
main.instance_eval { alias inspect to_s }

为了完整性。
另一种方法是使用全局变量:

$main = Object.new
class Object
  def $main.go
    @a = 1
    def m2
      puts @a
    end
    m2                            # 1
  end
end
$main.go
p Object.instance_methods(false)  # [:m2]
p $main.instance_variables        # [:@a]

当然,变量main/$maingo方法并不存在,但是当我想到这个想法时,我的脑海中就没有更多的缺陷了,这个想法就像你的代码被放入main的方法中,并通过运行该方法来执行。
这也解释了为什么在顶层定义的方法到处可见:
a.rb
一个一个三个一个一个
因为它们变成了Object的示例方法。
您还可以使用示例变量,它们是main对象的示例变量。

ssm49v7z

ssm49v7z6#

Ruby中的所有内容都发生在某个对象的上下文中,顶层的对象称为“main”,它基本上是Object的一个示例,具有一个特殊属性,即在那里定义的任何方法都被添加为Object的示例方法(因此它们在任何地方都可用)。
因此,我们可以创建一个完全由以下内容组成的脚本:

puts object_id
@a = 'Look, I have instance variables!'
puts @a

它将打印“105640”和“看,我有示例变量!"。
这不是你通常需要关心的事情,但它就在那里。

相关问题