只想询问正确的做法是什么。
我的偏好是使用过程,因为我认为在方法中定义方法有点不整洁,应该只在必要时才进行。为了解决它,我只是使用过程。
这样做的正确/更好的方法是什么?为什么? (除了proc能够访问自己定义的主要方法变量之外)
def meth( params_prime )
calculations = do_something_with_whatever
def sub_meth( params_sub )
do_something_with_params_sub
end
sub_meth_params(calculations) # is this better?
proc1 = proc{ |params_sub| do_something_with_params_sub }
proc1.call(calculations) # or is this?
end
答案 0 :(得分:1)
目前尚不清楚你的具体用例是什么,但我肯定会选择procs或lambdas。在动态定义proc或lambda时,开销较少,因此它们是可通过的,因此如果需要,您可以返回它们,并且可以在函数外部使用它们。
使用“def”将方法公开为当前方法范围之外的实例方法(因此在包含类中,在您的情况下可能为Object
)。这可能是也可能不是你想要的。如果要使用仅在本地范围内可用的匿名函数,请使用lambda。
Proc vs Lambda:我通常更喜欢使用lambdas,因为它们表现得更“可预测”,这意味着:正如您所期望的那样(检查传递的变量,并返回从lambda返回,proc从被调用的范围返回) 。但是从你的例子来看,很难推断出适用的内容。我认为关键的区别在于:lambas是可以传递的,因此表现得更加明智。如果这不是您的使用案例,请使用Proc
:)(差异为write-up)。
答案 1 :(得分:0)
定义方法内部的方法是Ruby的一个特性,可能有其用途。但有些东西告诉我,当你还是初学者级别的Rubyist时,你会问一个非常高级的问题。你知道默认的定义是什么吗?如果没有,check this article by Yugui。
Proc在Ruby中非常重要,但是新手倾向于使用它们而不是在适当的对象中定义方法,这就是我从你的问题中得到的确切气味。 Ruby系列OO语言中常用的方法是定义对象的方法:
class Foo
def bar *params
# do something with params
end
end
由于您不理解在方法中定义方法的含义,因此请在接下来的6个月内不要这样做。一旦理解了对象,就可以再次开始尝试这个非常高级的功能。
附录:
由于您表现得很有兴趣,让我告诉您在顶级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
但#baz还没有:
X.instance_methods.include? :baz
#=> false
只有在您至少调用#bar
一次后才能在X上定义方法:
X.new.bar
#=> "bar"
X.instance_methods.include? :baz
#=> true
现在我想请你欣赏刚刚发生的可怕事情:一个实例刚修改了它的母班。这是违规行为。违反OO设计这样一个基本原则,我甚至不确定它有一个名字。这种技术非常适合混淆编码竞赛,但在制作中,它是禁忌。 Ruby让你可以自由地打破这种禁忌,为你提供绳索,但你不能在任何正常情况下做到这一点。
那么什么可能比类定义中def
内的def
更糟糕?答案是,def
位于顶层的def
内。让我告诉你原因。通常,当您在顶层定义def
的方法时,默认的定义为Object
,但顶级定义成为对象的私有实例方法。这是为了防止顶级def
的意外后果,因为几乎所有Ruby对象都继承自Object
。例如,如果您定义:
class Object
def foo; "foo" end
end
现在你的所有对象都会响应foo:
foo #=> "foo"
1.foo #=> "foo"
[].foo #=> "foo
当我们在顶层定义方法时,我们通常只打算在顶层使用该方法,并且不希望每个对象都继承它。因此,顶级def
变为私有:
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
我们可以看到方法#hello
尚未成为Object
的实例方法:
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"
神秘地说,在顶层,我们可以在没有#send
的情况下调用这个私有方法:
hello
#=> "hello"
现在,当您在def
顶级def
进行def bar
def baz; "baz" end
"bar"
end
时会发生什么:
Object#bar
您以预期的方式定义私有实例方法Object#baz
。但是当你召唤它时,顶级魔法不再起作用,而公共方法bar #=> "bar"
被定义:
#baz
这样,不仅仅是顶层,而且每个Ruby对象都被1.baz #=> "baz"
Class.baz #=> "baz"
方法污染了:
{{1}}
这就是为什么我告诉你不要使用这个习惯用语,直到你从无意识无能的程度发展到有意识的无能水平。我建议您阅读有关top level methods in Ruby的更多信息。
答案 2 :(得分:0)
如果要使用sub_func从其他方法的调用中封装它,可以使用类将函数和sub_func组合在一起并使sub_func为private。否则,如果您希望将此函数作为参数进一步传递,则可以将其声明为lamda。
def func params_prime
sub_func = ->(params_sub){do_something_with_params}
sub_func.call(params_prime)
end