Tapi itu bukan metode bersarang. Saya ulangi: Ruby tidak memiliki metode bersarang.
Apa ini, adalah definisi metode dinamis. Saat Anda berlari meth1, tubuh meth1akan dieksekusi. Tubuh kebetulan mendefinisikan metode bernama meth2, itulah sebabnya setelah dijalankan meth1sekali, Anda bisa memanggil meth2.
Tapi dimana meth2didefinisikan? Yah, ini jelas tidak didefinisikan sebagai metode bersarang, karena tidak ada metode bersarang di Ruby. Ini didefinisikan sebagai metode contoh Test1:
Test1.new.meth2
# Yay
Selain itu, jelas akan ditentukan ulang setiap kali Anda menjalankan 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
Singkatnya: tidak, Ruby tidak mendukung metode bersarang.
Perhatikan juga bahwa di Ruby, badan metode tidak bisa menjadi closure, hanya badan blok yang bisa. Ini cukup banyak menghilangkan penggunaan kasus besar untuk metode bersarang, karena bahkan jika Ruby didukung metode bersarang, Anda tidak bisa menggunakan variabel metode luar dalam metode bersarang.
PEMBARUAN LANJUTAN: pada tahap selanjutnya , maka, sintaks ini mungkin digunakan kembali untuk menambahkan metode bersarang ke Ruby, yang akan berperilaku seperti yang saya jelaskan: mereka akan dicakup ke metode yang memuatnya, yaitu tidak terlihat dan tidak dapat diakses di luar metode penampungnya tubuh. Dan mungkin, mereka akan memiliki akses ke lingkup leksikal metode yang mereka isi. Namun, jika Anda membaca diskusi yang saya tautkan di atas, Anda dapat mengamati bahwa matz sangat menentang metode bersarang (tetapi masih untuk menghapus definisi metode bersarang).
Namun, Anda juga dapat menunjukkan cara membuat lambda penutupan dalam metode untuk KERING, atau menjalankan rekursi.
Phrogz
119
Saya merasa Ruby mungkin tidak memiliki metode bersarang.
Mark Thomas
16
@ Mark Thomas: Apakah saya lupa menyebutkan bahwa Ruby tidak memiliki metode bersarang? :-) Serius: pada saat saya menulis jawaban ini, sudah ada tiga jawaban, yang masing-masing menyatakan bahwa Ruby memang memiliki metode bersarang. Beberapa dari jawaban itu bahkan mendapat suara positif meski terang-terangan salah. Bahkan ada yang diterima oleh OP, lagi-lagi meski salah. Potongan kode yang digunakan jawaban untuk membuktikan bahwa Ruby mendukung metode bersarang, sebenarnya membuktikan sebaliknya, tetapi tampaknya baik upvoters maupun OP benar-benar peduli untuk memeriksanya. Jadi, saya memberikan satu jawaban yang benar untuk setiap kesalahan. :-)
Jörg W Mittag
10
Ketika Anda menyadari bahwa ini semua hanyalah instruksi untuk Kernel yang memodifikasi tabel dan bahwa metode dan kelas dan modul semua hanya entri dalam tabel dan tidak benar-benar nyata, Anda menjadi seperti Neo ketika dia melihat seperti apa Matrix itu. Kemudian Anda benar-benar dapat menjadi filosofis dan mengatakan bahwa selain metode bersarang, bahkan tidak ada metode. Bahkan tidak ada agen. Mereka adalah program dalam matriks. Bahkan steak juicy yang Anda makan hanyalah sebuah entri di meja.
mydoghasworms
3
Tidak ada metode, kode Anda hanyalah simulasi di The Matrix
bbozo
13
Sebenarnya itu mungkin. Anda dapat menggunakan procs / lambda untuk ini.
deftest(value)
inner = ->() {
value * value
}
inner.call()
end
Anda tidak salah, tetapi jawaban Anda dijabarkan sebagai solusi untuk mencapai metode bertingkat. Padahal pada kenyataannya Anda hanya menggunakan procs yang bukan merupakan metode. Ini adalah jawaban yang bagus di luar mengklaim untuk memecahkan "metode bersarang"
Brandon Buck
5
Tidak, tidak, Ruby memang memiliki metode bertingkat. Periksa ini:
defouter_method(arg)
outer_variable = "y"
inner_method = lambda {
puts arg
puts outer_variable
}
inner_method[]
end
outer_method "x"# prints "x", "y"
Ini berguna ketika Anda melakukan hal-hal seperti menulis DSL yang membutuhkan berbagi ruang lingkup antar metode. Tetapi sebaliknya, Anda jauh lebih baik melakukan hal lain, karena seperti jawaban yang lain, innerdidefinisikan ulang setiap kali outerdipanggil. Jika Anda menginginkan perilaku ini, dan terkadang Anda mungkin menginginkannya, ini adalah cara yang baik untuk mendapatkannya.
Cara Ruby adalah memalsukannya dengan peretasan yang membingungkan yang akan membuat beberapa pengguna bertanya-tanya "Bagaimana sih cara ini bisa bekerja?", Sementara yang kurang penasaran hanya akan menghafal sintaks yang diperlukan untuk menggunakan benda itu. Jika Anda pernah menggunakan Rake atau Rails, Anda pasti pernah melihat hal semacam ini.
Ini peretasan seperti itu:
defmlet(name,func)
my_class = (Class.new dodefinitialize(name,func)
@name=name
@func=func
enddefmethod_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"endendend)
yield my_class.new(name,func)
end
Apa yang dilakukannya adalah menentukan metode tingkat atas yang membuat kelas dan meneruskannya ke blok. Kelas menggunakan method_missinguntuk berpura-pura memiliki metode dengan nama yang Anda pilih. Ini "mengimplementasikan" metode dengan memanggil lambda yang harus Anda sediakan. Dengan menamai objek dengan nama satu huruf, Anda dapat meminimalkan jumlah pengetikan tambahan yang diperlukannya (yang sama dengan yang dilakukan Rails di dalamnya schema.rb). mletdinamai menurut bentuk Common Lisp flet, kecuali fsingkatan dari "function",m singkatan dari "method".
Dimungkinkan untuk membuat alat serupa yang memungkinkan beberapa fungsi dalam untuk didefinisikan tanpa tambahan bersarang, tetapi itu membutuhkan peretasan yang lebih buruk dari jenis yang mungkin Anda temukan dalam implementasi Rake atau Rspec. Mencari tahu bagaimana Rspec let!bekerja akan membawa Anda jauh untuk bisa menciptakan kekejian yang mengerikan.
Jawaban:
PEMBARUAN: Karena jawaban ini sepertinya mendapat perhatian akhir-akhir ini, saya ingin menunjukkan bahwa ada diskusi tentang pelacak masalah Ruby untuk menghapus fitur yang dibahas di sini, yaitu melarang memiliki definisi metode di dalam tubuh metode .
Tidak, Ruby tidak memiliki metode bertingkat.
Anda bisa melakukan sesuatu seperti ini:
class Test1 def meth1 def meth2 puts "Yay" end meth2 end end Test1.new.meth1
Tapi itu bukan metode bersarang. Saya ulangi: Ruby tidak memiliki metode bersarang.
Apa ini, adalah definisi metode dinamis. Saat Anda berlari
meth1
, tubuhmeth1
akan dieksekusi. Tubuh kebetulan mendefinisikan metode bernamameth2
, itulah sebabnya setelah dijalankanmeth1
sekali, Anda bisa memanggilmeth2
.Tapi dimana
meth2
didefinisikan? Yah, ini jelas tidak didefinisikan sebagai metode bersarang, karena tidak ada metode bersarang di Ruby. Ini didefinisikan sebagai metode contohTest1
:Test1.new.meth2 # Yay
Selain itu, jelas akan ditentukan ulang setiap kali Anda menjalankan
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
Singkatnya: tidak, Ruby tidak mendukung metode bersarang.
Perhatikan juga bahwa di Ruby, badan metode tidak bisa menjadi closure, hanya badan blok yang bisa. Ini cukup banyak menghilangkan penggunaan kasus besar untuk metode bersarang, karena bahkan jika Ruby didukung metode bersarang, Anda tidak bisa menggunakan variabel metode luar dalam metode bersarang.
PEMBARUAN LANJUTAN: pada tahap selanjutnya , maka, sintaks ini mungkin digunakan kembali untuk menambahkan metode bersarang ke Ruby, yang akan berperilaku seperti yang saya jelaskan: mereka akan dicakup ke metode yang memuatnya, yaitu tidak terlihat dan tidak dapat diakses di luar metode penampungnya tubuh. Dan mungkin, mereka akan memiliki akses ke lingkup leksikal metode yang mereka isi. Namun, jika Anda membaca diskusi yang saya tautkan di atas, Anda dapat mengamati bahwa matz sangat menentang metode bersarang (tetapi masih untuk menghapus definisi metode bersarang).
sumber
Sebenarnya itu mungkin. Anda dapat menggunakan procs / lambda untuk ini.
def test(value) inner = ->() { value * value } inner.call() end
sumber
Tidak, tidak, Ruby memang memiliki metode bertingkat. Periksa ini:
def outer_method(arg) outer_variable = "y" inner_method = lambda { puts arg puts outer_variable } inner_method[] end outer_method "x" # prints "x", "y"
sumber
Anda bisa melakukan sesuatu seperti ini
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
Ini berguna ketika Anda melakukan hal-hal seperti menulis DSL yang membutuhkan berbagi ruang lingkup antar metode. Tetapi sebaliknya, Anda jauh lebih baik melakukan hal lain, karena seperti jawaban yang lain,
inner
didefinisikan ulang setiap kaliouter
dipanggil. Jika Anda menginginkan perilaku ini, dan terkadang Anda mungkin menginginkannya, ini adalah cara yang baik untuk mendapatkannya.sumber
Cara Ruby adalah memalsukannya dengan peretasan yang membingungkan yang akan membuat beberapa pengguna bertanya-tanya "Bagaimana sih cara ini bisa bekerja?", Sementara yang kurang penasaran hanya akan menghafal sintaks yang diperlukan untuk menggunakan benda itu. Jika Anda pernah menggunakan Rake atau Rails, Anda pasti pernah melihat hal semacam ini.
Ini peretasan seperti itu:
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
Apa yang dilakukannya adalah menentukan metode tingkat atas yang membuat kelas dan meneruskannya ke blok. Kelas menggunakan
method_missing
untuk berpura-pura memiliki metode dengan nama yang Anda pilih. Ini "mengimplementasikan" metode dengan memanggil lambda yang harus Anda sediakan. Dengan menamai objek dengan nama satu huruf, Anda dapat meminimalkan jumlah pengetikan tambahan yang diperlukannya (yang sama dengan yang dilakukan Rails di dalamnyaschema.rb
).mlet
dinamai menurut bentuk Common Lispflet
, kecualif
singkatan dari "function",m
singkatan dari "method".Anda menggunakannya seperti ini:
def outer mlet :inner, ->(x) { x*2 } do |c| c.inner 12 end end
Dimungkinkan untuk membuat alat serupa yang memungkinkan beberapa fungsi dalam untuk didefinisikan tanpa tambahan bersarang, tetapi itu membutuhkan peretasan yang lebih buruk dari jenis yang mungkin Anda temukan dalam implementasi Rake atau Rspec. Mencari tahu bagaimana Rspec
let!
bekerja akan membawa Anda jauh untuk bisa menciptakan kekejian yang mengerikan.sumber
:-D
Ruby memiliki metode bertingkat, hanya saja metode tersebut tidak melakukan apa yang Anda harapkan
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"
sumber