Çevrimiçi yazılımda rastgele konular okurken ördek yazarak geçtim ve tam olarak anlamadım.
“Ördek yazma” nedir?
Çevrimiçi yazılımda rastgele konular okurken ördek yazarak geçtim ve tam olarak anlamadım.
“Ördek yazma” nedir?
Yanıtlar:
Güçlü yazımları olmayan dinamik dillerde kullanılan bir terimdir .
Fikir, bir nesne üzerinde var olan bir yöntemi çağırmak için bir türe ihtiyacınız olmamasıdır - üzerinde bir yöntem tanımlanmışsa, onu çağırabilirsiniz.
Adı "Ördek gibi görünüyor ve ördek gibi quacks, o bir ördek" ifadesinden geliyor.
Wikipedia çok daha fazla bilgiye sahip.
Ördek yazımı , bir işlemin , işlenenlerinin yerine getirmesi gereken gereksinimleri resmi olarak belirtmediği , ancak verilenle denediği anlamına gelir .
Diğerlerinin söylediklerinden farklı olarak, bunun dinamik diller veya miras sorunları ile ilgili olması gerekmez.
Örnek görev:Quack
Bir nesne üzerindeki bazı yöntemleri çağırın .
Olmadan ördek-yazma kullanılırken, bir işlev f
bu görevi yapıyor onun argümanı bazı yöntem desteklemek zorunda olduğu önceden belirtmek zorundadır Quack
. Ortak bir yol, arayüzlerin kullanılmasıdır
interface IQuack {
void Quack();
}
void f(IQuack x) {
x.Quack();
}
Arama f(42)
başarısız oluyor, ancak bir -subtype örneği f(donald)
olduğu sürece çalışıyor .donald
IQuack
Başka bir yaklaşım yapısal yazımdır - ancak yine de yöntem Quack()
, quack
önceden derleyici hatasına neden olacağını kanıtlayamayan herhangi bir şey resmi olarak belirtilir .
def f(x : { def Quack() : Unit }) = x.Quack()
Hatta yazabiliriz
f :: Quackable a => a -> IO ()
f = quack
Haskell'de, Quackable
tip sınıfının yöntemimizin varlığını sağlaması.
Dediğim gibi, bir ördek yazım sistemi gereksinimleri belirtmiyor, sadece bir şey işe yarıyorsa çalışır .
Böylece, Python'lar gibi dinamik bir tip sistem her zaman ördek yazmayı kullanır:
def f(x):
x.Quack()
Bir destekleyici f
alırsa , her şey yolunda, eğer değilse, çalışma zamanında çökecektir.x
Quack()
Ancak ördekle yazma, dinamik yazma anlamına gelmez - aslında, herhangi bir gereksinim vermeyen çok popüler ama tamamen statik bir ördek yazma yaklaşımı da vardır:
template <typename T>
void f(T x) { x.Quack(); }
Fonksiyon bazı istediği herhangi bir şekilde söylemez x
o kutuyu Quack
bunun yerine sadece çalışır, derleme sırasında 's ince ve her şey çalışıp çalışmadığını.
def f(x)
yerine def f(IQuack x)
.
Sorunun anlambiliminin tartışılması oldukça nüanslıdır (ve çok akademiktir), ancak genel fikir şudur:
Ördek Yazma
(“Ördek gibi yürür ve ördek gibi quacks yaparsa o zaman bir ördek.”) - EVET! ama bu ne anlama geliyor ??! Bu en iyi örnek olarak gösterilmiştir:
Ördek Yazma işlevselliğine örnekler:
Sihirli bir asam olduğunu hayal et. Özel güçleri var. Asayı sallayıp "Sür!" o zaman, araba sürüyor!
Başka şeyler üzerinde çalışıyor mu? Emin değilim: bir kamyonda deniyorum. Vay canına - o da sürüyor! Sonra uçaklar, trenler ve 1 Woods üzerinde denemek (onlar 'golf topu' sürücü 'için kullandıkları golf kulübü türüdür). Hepsi sürüyor!
Ama bir çay fincanı muydu? Hata: KAAAA-BOOOOOOM! o kadar iyi sonuç vermedi. ====> Çay bardakları araba kullanamaz !! yaa !?
Temelde ördek yazma kavramı budur. Satın almadan önce bir dene sistemi. Çalışırsa, her şey yolunda. Ama eğer başarısız olursa, hala elindeki bir el bombası gibi, yüzüne patlayacak.
Diğer bir deyişle, biz nesne ne ilgilendiğiniz yapabilirsiniz diğerlerinden ziyade nesnenin ne .
Örnek: statik olarak yazılan diller
Biz ilgilenen olsaydı nesne aslında ne , o zaman bizim sihir sadece önceden seti, yetkili türleri üzerinde çalışacak - bu durumda otomobillere değil sürebilirsin diğer nesneler üzerinde başarısız olur : kamyon, motosiklet, tuk tuks vs. Kamyonlarda çalışmaz çünkü sihirli değnekimiz sadece arabalarda çalışmasını bekler .
Başka bir deyişle, bu senaryoda, sihirli değnek , nesnenin yapabileceği şeyden (örneğin, arabalar, kamyonlar vb. Gidip gelemeyeceği) nesnenin ne olduğuna (bir araba mı?) Çok yakından bakar .
Bir şekilde büyü alabilirsiniz asa kamyonlar hem beklemek eğer sürücüye bir kamyon almak tek yolu ve ( "ortak bir arabirim uygulama" ile belki) arabalar. Bunun ne anlama geldiğini bilmiyorsanız, o an için onu görmezden gelin.
Özet: Anahtar çıkarma
Ne ördek yazarak içinde önemli olan nesne aslında ne yapmak yerine nesne olandan ise .
Bir nesneyi alan Bird
ve walk()
yöntemini çağıran basit bir işlev tasarladığınızı düşünün . Düşünebileceğiniz iki yaklaşım vardır:
Bird
, yoksa kodları derlenmeyecektir. Herkes benim işlevi kullanmak istiyorsa, o sadece kabul farkında olmalıdır Bird
sobjects
ve ben sadece nesnenin walk()
yöntemini çağırıyorum . Yani, eğer object
kutu walk()
doğruysa, yapamazsa fonksiyonum başarısız olur. Yani burada nesnenin bir Bird
şey ya da başka bir şey olması önemli değil, yapabilmesi önemlidir walk()
(Bu ördek yazmasıdır )Göz önüne alınmalıdır ördek yazarak örnek Python kullanımlar için, bazı durumlarda yararlı olabilir yazarak ördek çok.
Wikipedia'nın oldukça ayrıntılı bir açıklaması var:
http://en.wikipedia.org/wiki/Duck_typing
ördek yazma, bir nesnenin geçerli yöntem ve özellik kümesinin, belirli bir sınıftan miras alınması veya belirli bir arabirimin uygulanmasından ziyade geçerli semantiği belirlediği bir dinamik yazma tarzıdır.
Önemli not, ördek yazarken bir geliştiricinin, nesnenin asıl altta yatan türden ziyade tüketilen parçaları ile daha fazla ilgilenmesi muhtemeldir.
Eski deyimi tekrarlayan birçok cevap görüyorum:
Ördek gibi görünüyor ve ördek gibi quacks, bu bir ördek
ve sonra ördek yazarak neler yapabileceğinizin açıklamasına veya konsepti daha da gizleyen bir örneğe dalın.
Çok fazla yardım bulamıyorum.
Bu bulduğum ördek yazmayla ilgili düz bir İngilizce cevap en iyi girişimdir:
Ördek Yazma, bir nesnenin ne olduğu ile değil, ne yapabileceği ile tanımlandığı anlamına gelir.
Bu, bir nesnenin sınıfı / türü ile daha az ve onun üzerinde hangi yöntemlerin çağrılabileceği ve üzerinde hangi işlemlerin gerçekleştirilebileceğiyle daha fazla ilgili olduğumuz anlamına gelir. Türünü önemsemiyoruz, ne yapabileceğini önemsiyoruz .
Ördek yazarak:
Ördek gibi konuşuyor ve yürüyorsa, o zaman bir ördek
Bu genellikle denir kaçırma ( dışaçekimsel muhakeme ya da adlandırılan retroduction sanırım daha net tanım):
dan C (Sonuç, gördüğümüz ) ve R (kural, ne biliyoruz ), biz karar kabul / / varsayalım P (Önerme, mülkiyet başka bir deyişle belirli bir gerçeği)
... tıbbi teşhisin temeli
ördekler ile: C = yürüyüşler, görüşmeler , R = ördek gibi , P = ördek
Programlamaya geri dön:
Nesne O yöntemi / özellik vardır MP1 ve arayüz / tip T gerektirir / tanımlar MP1
Nesne O yöntemi / özellik vardır MP2 ve arayüz / tip T gerektirir / tanımlar MP2
...
Yani, daha basit kabul etmektense MP1 sürece bazı tanımını karşılayan olduğu gibi herhangi bir nesne üzerinde ... MP1 iddiası ile ..., derleyici / çalışma zamanı da tamam olmalıdır o tip taşımaktadır T
Ve yukarıdaki örneklerde durum böyle mi? Ördek yazmak aslında hiç yazmak değil midir? Yoksa örtük yazma mı demeliyiz?
Dilin kendisine bakmak yardımcı olabilir; genellikle bana yardımcı olur (ben anadili İngilizce değilim).
İçinde duck typing
:
1) kelime typing
klavyede yazmak anlamına gelmez (aklımdaki kalıcı görüntü gibi), " bu şey ne tür bir şey? "
2) duck
bu tespitin nasıl yapıldığını ifade eder; "gevşek" bir belirleyici. " Ördek gibi yürüyorsa ... o zaman bir ördek ". 'Gevşek' çünkü şey bir ördek olabilir ya da olmayabilir, ama aslında bir ördek olup olmadığı önemli değil; önemli olan ördeklerle yapabileceğim ve ördeklerin sergilediği davranışları beklediğim. Ekmek kırıntılarını besleyebilirim ve şey bana doğru gidebilir veya bana şarj edebilir ya da geri çekilebilir ... ama beni bir grizzly gibi yiyip bitmeyecek.
Genel cevap vermediğimi biliyorum. Ruby'de, değişken veya yöntem türlerini beyan etmiyoruz - her şey sadece bir tür nesne. Kural "Sınıflar Tür Değildir"
Ruby'de sınıf asla (Tamam, neredeyse hiç) tür değildir. Bunun yerine, bir nesnenin türü, o nesnenin yapabilecekleriyle daha fazla tanımlanır. Ruby'de, bu ördek yazmaya diyoruz. Bir nesne ördek gibi yürür ve ördek gibi konuşursa, tercüman ona ördekmiş gibi davranmaktan mutluluk duyar.
Örneğin, bir dizeye şarkı bilgisi eklemek için bir rutin yazıyor olabilirsiniz. Bir C # veya Java arka planından geliyorsanız, bunu yazmaya cazip gelebilirsiniz:
def append_song(result, song)
# test we're given the right parameters
unless result.kind_of?(String)
fail TypeError.new("String expected") end
unless song.kind_of?(Song)
fail TypeError.new("Song expected")
end
result << song.title << " (" << song.artist << ")" end
result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"
Ruby'nin ördek yazmasını kucaklayın ve çok daha basit bir şey yazın:
def append_song(result, song)
result << song.title << " (" << song.artist << ")"
end
result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"
Bağımsız değişkenlerin türünü kontrol etmenize gerek yoktur. << (sonuç durumunda) veya başlık ve sanatçıyı (şarkı durumunda) destekliyorlarsa, her şey işe yarayacaktır. Yapmazlarsa, yönteminiz yine de bir istisna atar (tıpkı türleri kontrol ederseniz yapmış olacağı gibi). Ancak kontrol olmadan, yönteminiz aniden çok daha esnektir. << kullanarak eklenen bir dizi, dize, dosya veya başka bir nesneyi iletebilirsiniz ve bu sadece işe yarayacaktır.
Ördek Yazma Tipi İpucu değil!
Temel olarak "ördek yazmayı" kullanmak için, ortak bir arabirim kullanarak belirli bir türü değil, daha geniş bir alt türü (kalıtımdan bahsetmiyorum, alt türlerden bahsettiğimde aynı profillere uyan "şeyleri kastediyorum) hedefleyeceksiniz. .
Bilgi depolayan bir sistem hayal edebilirsiniz. Bilgi yazmak / okumak için bir çeşit depolama alanına ve bilgiye ihtiyacınız vardır.
Depolama türleri şunlar olabilir: dosya, veritabanı, oturum vb.
Arabirim, depolama türünden bağımsız olarak kullanılabilir seçenekleri (yöntemleri) size bildirir, yani bu noktada hiçbir şey uygulanmaz! Başka bir deyişle, Arayüz bilginin nasıl saklanacağı hakkında hiçbir şey bilmiyor.
Her depolama sistemi, aynı yöntemleri uygulayarak arabirimin varlığını bilmelidir.
interface StorageInterface
{
public function write(string $key, array $value): bool;
public function read(string $key): array;
}
class File implements StorageInterface
{
public function read(string $key): array {
//reading from a file
}
public function write(string $key, array $value): bool {
//writing in a file implementation
}
}
class Session implements StorageInterface
{
public function read(string $key): array {
//reading from a session
}
public function write(string $key, array $value): bool {
//writing in a session implementation
}
}
class Storage implements StorageInterface
{
private $_storage = null;
function __construct(StorageInterface $storage) {
$this->_storage = $storage;
}
public function read(string $key): array {
return $this->_storage->read($key);
}
public function write(string $key, array $value): bool {
return ($this->_storage->write($key, $value)) ? true : false;
}
}
Şimdi, her bilgi yazmanız / okumanız gerektiğinde:
$file = new Storage(new File());
$file->write('filename', ['information'] );
echo $file->read('filename');
$session = new Storage(new Session());
$session->write('filename', ['information'] );
echo $session->read('filename');
Bu örnekte Depolama yapıcısında Ördek Yazma özelliğini kullanacaksınız:
function __construct(StorageInterface $storage) ...
Umarım yardımcı olmuştur;)
Dinamik yazım, statik yazım ve ördek yazmayı karıştırmanın karışık olduğunu düşünüyorum. Ördek yazımı bağımsız bir kavramdır ve Go gibi statik olarak yazılan bir dil, ördek yazmayı uygulayan bir tür kontrol sistemine sahip olabilir. Bir tür sistemi, (bildirilen) bir nesnenin yöntemlerini kontrol eder, ancak türü değil, buna ördek yazma dili denebilir.
Ünlü cümleyi kendi yolumda anlamaya çalışıyorum: "Bir nesnenin umrunda olmayan Python dozu gerçek bir ördek mi, değil mi. Tek umurunda olan şey, ilk 'quack', ikinci 'ördek gibi'.
İyi bir web sitesi var. http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14
Yazar, ördek yazmanın kendi iç veri yapısına sahip olan ancak normal Python sözdizimi kullanılarak erişilen kendi sınıflarınızı oluşturmanıza izin verdiğini belirtti.