Bir yöntemin içinde bir yöntemim var. İç yöntem, çalıştırılan değişken bir döngüye bağlıdır. Bu kötü bir fikir mi?
Yanıtlar:
GÜNCELLEME: Bu yanıt son zamanlarda biraz ilgi aldık görünüyor beri olduğu işaret etmek istediği tartışma için Yakut sorun izleyicide üzerinde kaldırmak özellik yani için, burada tartışılan korusun bir yöntem vücudun içinde yöntem tanımlarını sahip .
Hayır, Ruby'de yuvalanmış yöntemler yoktur.
Bunun gibi bir şey yapabilirsiniz:
class Test1
def meth1
def meth2
puts "Yay"
end
meth2
end
end
Test1.new.meth1
Ancak bu iç içe geçmiş bir yöntem değildir . Tekrar ediyorum: Yakut yoktur iç içe yöntemleri.
Bu, dinamik bir yöntem tanımıdır. Koştuğun zaman meth1
, bedeni meth1
idam edilecek. Gövde sadece adlandırılmış bir yöntemi tanımlar meth2
, bu yüzden bir meth1
kez çalıştırdıktan sonra,meth2
.
Ama nerede meth2
tanımlanıyor? Eh, belli ki oluyor değil orada beri, iç içe geçmiş bir yöntem olarak tanımlanan hiçbir vardır Ruby iç içe yöntemleri. Aşağıdakilerin bir örnek yöntemi olarak tanımlanır Test1
:
Test1.new.meth2
# Yay
Ayrıca, her çalıştırdığınızda açıkça yeniden tanımlanacaktır meth1
:
Test1.new.meth1
# Yay
Test1.new.meth1
# test1.rb:3: warning: method redefined; discarding old meth2
# test1.rb:3: warning: previous definition of meth2 was here
# Yay
Kısacası: hayır, Yakut gelmez iç içe yöntemleri destekler.
Ruby'de yöntem gövdelerinin kapanış olamayacağını, yalnızca blok gövdelerinin yapabileceğini unutmayın. Bu hemen hemen ortadan kaldırır bile bu yana iç içe yöntemleri için başlıca kullanım amaçlarından, eğer Yakut iç içe yöntemleri desteklenen, iç içe geçmiş yönteminde dış yöntemin değişkenleri kullanamadı.
GÜNCELLEME DEVAM EDİYOR: Daha sonraki bir aşamada, bu sözdizimi, Ruby'ye iç içe geçmiş yöntemler eklemek için yeniden kullanılabilir, bu da benim tanımladığım şekilde davranır: kapsama yöntemlerine göre kapsama alınır, yani içerme yöntemlerinin dışında görünmez ve erişilemez. vücut. Ve muhtemelen, içerme yöntemlerinin sözlü kapsamına erişebilirlerdi. Bununla birlikte, yukarıda bağladığım tartışmayı okursanız, matz'in iç içe geçmiş yöntemlere büyük ölçüde karşı olduğunu (ancak yine de yuvalanmış yöntem tanımlarını kaldırmak için) görebilirsiniz.
Aslında mümkün. Bunun için procs / lambda kullanabilirsiniz.
def test(value)
inner = ->() {
value * value
}
inner.call()
end
Hayır, hayır, Ruby iç içe geçmiş yöntemlere sahiptir. Şuna göz at:
def outer_method(arg)
outer_variable = "y"
inner_method = lambda {
puts arg
puts outer_variable
}
inner_method[]
end
outer_method "x" # prints "x", "y"
Bunun gibi bir şey yapabilirsin
module Methods
define_method :outer do
outer_var = 1
define_method :inner do
puts "defining inner"
inner_var = outer_var +1
end
outer_var
end
extend self
end
Methods.outer
#=> defining inner
#=> 1
Methods.inner
#=> 2
Bu, yöntemler arasında kapsam paylaşımı gerektiren DSL'ler yazmak gibi şeyler yaparken kullanışlıdır. Ama aksi takdirde, başka bir şey yapmaktan çok daha iyi olursunuz çünkü diğer cevapların da söylediği gibi inner
, her outer
çağrıldığında yeniden tanımlanır . Bu davranışı istiyorsanız ve bazen isteyebilirsiniz, bu onu elde etmenin iyi bir yoludur.
Ruby'nin yolu, bazı kullanıcıların "Bu nasıl oluyor da işe yarıyor?" Daha önce Rake veya Rails kullandıysanız, bu tür şeyler görmüşsünüzdür.
İşte böyle bir hack:
def mlet(name,func)
my_class = (Class.new do
def initialize(name,func)
@name=name
@func=func
end
def method_missing(methname, *args)
puts "method_missing called on #{methname}"
if methname == @name
puts "Calling function #{@func}"
@func.call(*args)
else
raise NoMethodError.new "Undefined method `#{methname}' in mlet"
end
end
end)
yield my_class.new(name,func)
end
Bunun yaptığı şey, bir sınıf oluşturan ve onu bir bloğa geçiren üst düzey bir yöntemi tanımlamaktır. Sınıf, method_missing
seçtiğiniz ada sahip bir yöntemi varmış gibi davranmak için kullanır . Sağlamanız gereken lambdayı çağırarak yöntemi "uygular". Nesneyi tek harfli bir adla adlandırarak, gerektirdiği fazladan yazma miktarını en aza indirebilirsiniz (bu, Rails'in içinde yaptığı şeyle aynıdır schema.rb
). "function" anlamına gelen yer dışında mlet
, Common Lisp formundan sonra adlandırılır ,flet
f
m
anlamına gelen "method" anlamına .
Bunu şu şekilde kullanırsın:
def outer
mlet :inner, ->(x) { x*2 } do |c|
c.inner 12
end
end
Ek yuvalama olmadan birden fazla iç işlevin tanımlanmasına izin veren benzer bir mekanizma yapmak mümkündür, ancak bu, Rake veya Rspec uygulamasında bulabileceğiniz türde daha da çirkin bir hack gerektirir. Rspec'in let!
çalışmalarının size böylesine korkunç bir iğrençlik yaratma yolunda size uzun bir yol sağlayacağını anlamak .
:-D
Ruby iç içe geçmiş yöntemlere sahiptir, ancak onlar beklediğiniz şeyi yapmaz
1.9.3p484 :001 > def kme; 'kme'; def foo; 'foo'; end; end
=> nil
1.9.3p484 :003 > self.methods.include? :kme
=> true
1.9.3p484 :004 > self.methods.include? :foo
=> false
1.9.3p484 :005 > kme
=> nil
1.9.3p484 :006 > self.methods.include? :foo
=> true
1.9.3p484 :007 > foo
=> "foo"