在Ruby方法中,我应该创建proc还是方法?

在Ruby方法中,我应该创建proc还是方法?,ruby,methods,proc,Ruby,Methods,Proc,我只是想问一下什么是正确的做法 我更喜欢使用procs,只是因为我认为在methods中定义方法有点不整洁,应该只在必要时进行。为了解决这个问题,我只需要使用procs 正确/更好的方法是什么?为什么?(除了proc访问在其自身之前定义的主方法变量的能力之外) 在方法中定义方法是Ruby的一个特性,它可能有自己的用途。但有些事情告诉我,你问的是一个非常高级的问题,而你仍然是一个初学者。你知道默认定义是什么吗?如果没有 进程在Ruby中非常重要,但是新手倾向于使用它们,而不是在适当的对象中定义方法

我只是想问一下什么是正确的做法

我更喜欢使用procs,只是因为我认为在methods中定义方法有点不整洁,应该只在必要时进行。为了解决这个问题,我只需要使用procs

正确/更好的方法是什么?为什么?(除了proc访问在其自身之前定义的主方法变量的能力之外)


在方法中定义方法是Ruby的一个特性,它可能有自己的用途。但有些事情告诉我,你问的是一个非常高级的问题,而你仍然是一个初学者。你知道默认定义是什么吗?如果没有

进程在Ruby中非常重要,但是新手倾向于使用它们,而不是在适当的对象中定义方法,这正是我从你的问题中得到的味道。在Ruby系列的OO语言中,通常的做法是在对象上定义方法:

class Foo
  def bar *params
    # do something with params
  end
end
因为您不理解在方法中定义方法的含义,所以在接下来的6个月内不要这样做。一旦您了解了对象,就可以再次开始尝试这个非常高级的功能

附件:

既然您演示了intrest,那么让我向您演示在顶级使用
def
中的
def
是一件令人不快的事情。通常,当您在某个类上定义方法而不进行进一步修饰时,它将成为该类的公共实例方法:

class X
  def foo; "foo" end
end

X.instance_methods.include? :foo
#=> true
def
中使用
def
时,内部def的定义对象将是
X

class X
  def bar
    def baz
      "baz"
    end
    "bar"
  end
end
执行上述代码时,实例方法#bar将在X上定义:

X.instance_methods.include? :bar
#=> true
X.new.bar
#=> "bar"
X.instance_methods.include? :baz
#=> true
但是#巴兹还没有:

X.instance_methods.include? :baz
#=> false
只有在调用
#bar
至少一次后,该方法才会在X上定义:

X.instance_methods.include? :bar
#=> true
X.new.bar
#=> "bar"
X.instance_methods.include? :baz
#=> true
现在我想请你们理解刚才发生了多么可怕的事情:一个实例修改了它的母类。那是违法行为。这违反了OO设计的基本原则,我甚至不确定它是否有名字。这项技术对于模糊编码竞争非常有用,但在生产中,这是禁忌。Ruby给了你打破禁忌的自由,给了你自缢的绳索,但在任何正常情况下你都不会这么做

那么,还有什么比类定义中的
def
内部的
def
更糟糕呢?答案是,在顶层的
def
内部有一个
def
。让我告诉你为什么。通常,当您在顶级使用
def
定义方法时,默认的定义对象是
Object
,但顶级定义成为Object的私有实例方法。这是为了防止顶级
def
s的意外后果,因为几乎所有Ruby对象都继承自
Object
。例如,如果您定义:

class Object
  def foo; "foo" end
end
现在,所有对象都将响应foo:

foo        #=> "foo"
1.foo      #=> "foo"
[].foo     #=> "foo
当我们在顶层定义方法时,我们通常只打算在顶层使用该方法,而不希望每个对象都继承它。因此,顶级
def
s变为私有:

hello      #=> NameError: undefined local variable or method `hello' for main:Object
1.hello    #=> NoMethodError: undifined method 'hello' for 1:Fixnum
现在我们在顶层使用
def

def hello; "hello" end
def bar
  def baz; "baz" end
  "bar"
end
我们可以看到,方法
#hello
is并没有成为
对象
的实例方法:

Object.instance_methods.include? :hello
#=> false
神秘的是,它成了它的私人方法:

Object.private_instance_methods.include? :hello
#=> true
这样,我们就避免了为每个对象定义
#hello
方法的意外后果。但是遗产就在那里。错误消息已更改:

1.hello    #=> NoMethodError: private method 'hello' called for 1:Fixnum
我们可以通过
#send
强制调用该方法:

1.send :hello
#=> "hello"
hello
#=> "hello"
奇怪的是,在顶层,我们可以调用这个私有方法,而无需
#send

1.send :hello
#=> "hello"
hello
#=> "hello"
现在,在顶层执行
def
中的
def
时会发生什么情况:

def hello; "hello" end
def bar
  def baz; "baz" end
  "bar"
end
您可以按照预期的方式定义私有实例方法
Object#bar
。但是当你调用它时,唉,顶级魔法不再起作用,一个公共方法
Object#baz
被定义:

bar      #=> "bar"
这样,不仅是顶层,而且每个Ruby对象都被您的
#baz
方法污染了:

1.baz       #=> "baz"
Class.baz   #=> "baz"

这就是为什么我告诉你不要使用这个成语,直到你从无意识的无能发展到有意识的无能。我建议您阅读更多信息。

如果您想使用sub_func从其他方法的调用中封装它,您可以使用类将函数和sub_func分组在一起,并将sub_func设为私有。否则,如果要将此函数作为参数进一步传递,可以将其声明为lamda

def func params_prime
  sub_func = ->(params_sub){do_something_with_params}  
  sub_func.call(params_prime)
end

不清楚您的具体用例是什么,但我肯定会选择procs或lambdas。动态定义proc或lambda时,开销较小,它们是可以通过的,因此如果需要,您可以返回它们,并且可以在函数外部使用它们

使用“def”将该方法公开为当前方法范围之外的实例方法(因此在包含类中,在您的情况下可能是
Object
)。这可能是你想要的,也可能不是。如果要使用仅在本地作用域中可用的匿名函数,请使用lambda


还有Proc vs Lambda:我通常更喜欢使用Lambda,因为它们的行为更“可预测”,这意味着:正如您所期望的那样(检查传递的变量,只返回Lambda的返回,Proc从被调用的范围返回)。但是从你的例子很难推断出什么是适用的。我认为关键的区别在于:lambas是可以传递的,因此表现得更理智一点。如果这不是您的用例,请使用
Proc
:)(一个不同点)。

对您来说,听起来居高临下的只是我想带您去。另外,当你实际指的是一种方法时,不要使用理论术语“函数”,这两者在术语上有细微的区别。
def
中的
def
将在默认定义对象上定义。在顶层,默认的definee是Object,但是