Neden lifleri ihtiyacımız var
Klasik bir örnek var Elyaflar için: Fibonacci sayıları oluşturuluyor
fib = Fiber.new do
x, y = 0, 1
loop do
Fiber.yield y
x,y = y,x y
end
end
Neden Lifleri burada ihtiyacımız var mı? Sadece aynı Proc (kapatma, aslında bu yeniden yazabilirim
def clsr
x, y = 0, 1
Proc.new do
x, y = y, x y
x
end
end
Bu yüzden
10.times { puts fib.resume }
ve
prc = clsr
10.times { puts prc.call }
sadece aynı sonucu döndürecektir.
Lifler avantajları vardır. Lifler ile yazabilirim ne Lambda ve diğer serin Ruby özellikleri ile yapamam?
CEVAP
Lifler muhtemelen asla doğrudan düzey bir uygulama kod içerisinde kullanılacak bir şey. Daha sonra yüksek düzey kodu kullanan diğer soyutlamalar oluşturmak için kullanabileceğiniz bir akış-kontrol ilkel.
Muhtemelen Ruby liflerin #1 kullanımı Ruby 1.9 çekirdek Ruby bir sınıf olan Enumerator
s, uygulamaktır. Buinanılmazyararlı.
Ruby 1.9, çekirdek sınıfları neredeyse herhangi bir yineleyici yöntemi ararsanolmadanbir blok geçirilmesi, Enumerator
dönecektir.
irb(main):001:0> [1,2,3].reverse_each
=> #<Enumerator: [1, 2, 3]:reverse_each>
irb(main):002:0> "abc".chars
=> #<Enumerator: "abc":chars>
irb(main):003:0> 1.upto(10)
=> #<Enumerator: 1:upto(10)>
Enumerator
s Bu Sayısız nesneler ve each
kendi yöntemleri ile blok çağrılmıştı özgün yineleyici yöntemi ile elde edilmiş olan element verim. Verdiğim örnekte, Numaralandırıcısı reverse_each
tarafından döndürülen 3,2,1 veren each
bir yöntemi vardır. Numaralandırıcısı chars
verimleri tarafından döndürülen "c","b","" (ve benzeri). AMA, orijinal yineleyici yöntemi aksine, Numaralandırıcısı ayrıca eğer next
ararsan bir tek arda: elemanları dönebilirsiniz
irb(main):001:0> e = "abc".chars
=> #<Enumerator: "abc":chars>
irb(main):002:0> e.next
=> "a"
irb(main):003:0> e.next
=> "b"
irb(main):004:0> e.next
=> "c"
Duymuş olabilirsiniz, "iç kullanımına" ve "(her ikisi de iyi bir açıklama" Gang of Four "Tasarım Desenleri kitap). verilen" dış kullanımına Yukarıdaki örnek Sıralayıcısını bir dış bir iç yineleyici açmak için kullanılabilir olduğunu gösterir.
Bu kendi sıralayıcısını yapmak için bir yoldur:
class SomeClass
def an_iterator
# note the 'return enum_for...' pattern; it's very useful
# enum_for is an Object method
# so even for iterators which don't return an Enumerator when called
# with no block, you can easily get one by calling 'enum_for'
return enum_for(:an_iterator) if not block_given?
yield 1
yield 2
yield 3
end
end
Deneyelim:
e = SomeClass.new.an_iterator
e.next # => 1
e.next # => 2
e.next # => 3
Bir dakika... garip bir şey var gibi görünüyor mu? Düz çizgi kod olarak an_iterator
27 *ifadeleri yazdı, ama Numaralandırıcısı onları çalıştırabilirsinizbir defada bir. next
, an_iterator
yürütme çağrılar arasında"". dondurulmuş Her zaman yield
aşağıdaki açıklamaya çalışan bir aşağı devam eder, ve sonra "" tekrar. donuyor next
, çağrı
Bu nasıl uygulandığını tahmin edebilir misiniz? Numaralandırıcısı bir lif an_iterator
çağrısı sarar, ve bir blok geçiriraskıya lif. Her zaman an_iterator
blok verir, çalışır durumda olan fiber askıya alınır, ve yürütme ana konu üzerinde devam ediyor. Bir dahaki sefere 35**, fiber kontrol geçer, diyorsunuzblok döndürürkaldığı yerden , ve an_iterator
devam ediyor.
Lifler olmadan bunu yapmak için gerekli ne olacağını düşünmek öğretici olacaktır. Hem iç hem de dış kullanımına sunmak istedim olan HER sınıf açık kod next
çağrılar arasında durumunu izlemek için içerir. Sonraki her arama bu durumu kontrol edin ve değeri iade etmeden önce güncelleme gerekiyor. Lifler ile yapabilirizotomatik olarakbir dış bir iç yineleyici dönüştürmek.
Bu mecbur değil ile lifler persay, ama bana söz bir şey daha yap Sıralayıcısını: izin sizin için geçerli üst düzey Sayısız yöntemleri için diğer kullanımına dışında each
. Düşünün: normalde tüm Sayısız yöntemleri, map
, select
, include?
, inject
, ve benzeri dahil olmak üzeretümelemanları each
tarafından bulunmuştur çalışın. Ama eğer bir nesne each
diğer dışında kullanımına varsa?
irb(main):001:0> "Hello".chars.select { |c| c =~ /[A-Z]/ }
=> ["H"]
irb(main):002:0> "Hello".bytes.sort
=> [72, 101, 108, 108, 111]
Herhangi bir engelleme ile yineleyici çağıran bir Numaralandırma döndürür, ve sonra diğer Sayısız yöntemleri çağırabilir.
Geri lifleri, Sayısız take
yöntemi kullandınız mı?
class InfiniteSeries
include Enumerable
def each
i = 0
loop { yield(i = 1) }
end
end
Eğer bir şey each
bu yöntem ararsa, asla dönmek gerekir gibi görünüyor? Şuna bir bak:
InfiniteSeries.new.take(10) # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Eğer bu başlık altında lifleri kullanır mı bilmiyorum, ama olabilir. Lifler bir dizi sonsuz listeleri ve tembel değerlendirme uygulamak için kullanılabilir. Bazı tembel yöntemleri örnek Sıralayıcısını ile tanımlanan, bazı burada tanımlıyorum: https://github.com/alexdowad/showcase/blob/master/ruby-core/collections.rb
Ayrıca genel amaçlı coroutine bir tesis lifleri kullanarak inşa edebilirsiniz. Henüz hiç benim programları coroutines kullandım ama bilmek güzel bir konsept.
Bu olasılıklar hakkında bir fikir verir umarım. Başta da dediğim gibi, lifler düşük seviyeli bir akış-kontrol ilkel. Mümkün kontrol-akış "" programı ("yer imleri" bir kitap) sayfalarında ve onları istediğiniz gibi. farklı pozisyonlar arasında geçiş gibi içinde birden fazla korumak için yapıyorlar Beri keyfi kod çalıştırmak bir lif, diyebilirsin içine 3. taraf kod üzerinde bir elyaf, ve sonra "freeze" ve devam ediyor, başka bir şey ne zaman geri arar kodunu kontrol.
Şöyle bir şey düşünün: birçok müşteri hizmet edecek. sunucu bir program yazıyoruz Bir istemci ile tam bir etkileşim bir dizi adım gitmektir, ama her bağlantı geçici ve bağlantıları arasında her istemci için devlet hatırlamak zorunda. (Web programlama gibi geliyor mu?)
Açıkça bu durumu saklamak, ve bir istemci bağlandığında her zaman kontrol etmek yerine ("adım" yapmak zorundalar), her müşteri için bir lif sağlamak. bir sonraki ne olduğunu görmek için İstemci belirledikten sonra, lif ve yeniden başlamak onların almak istiyorsunuz. Daha sonra her bağlantı sonunda, fiber askıya almak ve tekrar saklamak istiyorsunuz. Bu yol, düz çizgi kod tam bir etkileşim, tüm adımları dahil olmak üzere tüm mantığı doğal olarak program yerel olarak çalıştırmak için yapıldı gibi () uygulamak yazabilirsiniz.
Böyle bir şey pratik (en azından şimdilik) olmayabilir birçok nedeni var eminim, ama yine sadece bazı olasılıklar göstermeye çalışıyorum. ; Kavramı olsun, hiç kimse düşünmüş Henüz tamamen yeni Bazı uygulama ile gelebilir kim bilir!
Tam olarak Maven bir Anlık nedir ve ne...
Neden C Sanal Yöntemler ihtiyacımız va...
Neden monadlar ihtiyacımız var mı?...
#Pragma işaretlerinin önemi nedir? Ned...
Neden ve C boks kutulama ihtiyacımız v...