Özellikler yakın zamanda Mojo'ya tanıtıldı, bu yüzden onları deneyeyim diye düşündüm. Şu anda yerleşik özellikler arasında , , , , , ve yer alıyor ("-able" son eki bu adlandırma kurallarında yer alıyor gibi görünüyor!). Özellikler yapılar üzerinde çalışır. Bir özelliği uygulamak için, özellikle eşleşen bir yapıya bir yöntem eklemeniz yeterlidir; daha sonra özellik adını parametre olarak iletin: CollectionElement Copyable Destructable Intable Movable Sized Stringable @value struct Duck(Quackable): fn quack(self): print("Quack!") Mojo'daki dekoratörü , ve gibi yaşam döngüsü yöntemlerini yapıya ekleyerek, bunları kendimiz eklemek zorunda kalmadığımız için hayatımızı biraz basitleştirir. @value __init__() __copyinit__() __moveinit__() Mojo'daki özellikler henüz yöntemler için varsayılan uygulamaları desteklememektedir, dolayısıyla yukarıdaki yönteminin gövdesinde bulunmaktadır. Python'dakiyle aynı etkiye sahip olacak da kullanabilirsiniz. Quackable ... pass Mojo Özellikleri ve Go Arayüzleri Farklı isme rağmen Mojo'daki özelliklere yönelik temel yaklaşım bana Go arayüzlerini hatırlatıyor. Go'da bir yapısı tanımlayacak ve şöyle bir arayüzü uygulayacaksınız: Duck Quackable type Quackable interface { quack() } Ve bu arayüzü karşılayan bir yapı oluşturmak için: type Duck struct {} func (d Duck) quack() { fmt.Println("Quack!") } Bunu bir Mojo uygulamasıyla karşılaştırın: trait Quackable: fn quack(self): ... @value struct Duck(Quackable): fn quack(self): print("Quack!") Mojo versiyonunun daha da kısa olduğunu düşünüyorum; yöntemi tanımını yapı tipinin içine yerleştiriyor. Yapılar üzerinde çalışmanın yanı sıra, Mojo'daki özellikler, tıpkı Go'da olduğu gibi, bir anahtar sözcüğü gerektirmez. quack() Duck implements İlginç bir şekilde, Mojo belgelerinde varsayılan uygulamalara izin verilmediğine, yani bunlara gelecekte izin verilebileceğine dikkat çekiliyor. Bu, Mojo'nun, bir arayüzü değil, yapılara odaklanan Go'dan farklı bir yaklaşım izleyebileceği anlamına gelir. henüz uygulamaya tatmin eden Go'da varsayılan yöntem uygulamalarına gerek yoktur ve arayüz/özellik uygulaması Go'da mevcut olmayan bir kavram olduğundan benzer bir etki gömme ile elde edilir. Mojo'da işler farklı olabilir. Mojo Özellikleri Nasıl Kullanılır? Özelliklerin ve arayüzlerin değeri, kodu yeniden kullanılabilir kılmaktır. Mesela Mojo’da özellik tiplerini kabul eden fonksiyonlar yazabilirsiniz… fn make_it_quack[T: Quackable](could_be_duck: T): could_be_duck.quack() Ve sonra girdiyle aynı özelliği uygulayan farklı yapıları aktarın; her şey işe yarayacak! Örneğin, burada uygulayan bir yapısı var: Quackable Goose @value struct Goose(Quackable): fn quack(self): print("Honk!") Ve burada, hem hem de çağırmak için (unutmayın, programınıza giriş noktası olarak Mojo'daki işlevine ihtiyacınız vardır): Goose Duck make_it_quack main def main(): make_it_quack(Duck()) make_it_quack(Goose()) Bunun çıktısı olacak Quack! Honk! Özellik Hataları işlevine özelliğini uygulamayan bir şeyi (örneğin aktarmaya çalışırsam program derlenmez: make_it_quack Quackable StealthCow @value struct StealthCow(): pass make_it_quack(StealthCow()) Aşağıdaki hata mesajı daha açıklayıcı olabilirdi; belki Mojo ekibi bunu geliştirebilir? error: invalid call to 'make_it_quack': callee expects 1 input parameter, but 0 were specified yöntemini kaldırırsam da aynısı olur; burada güzel, açıklayıcı bir hata alıyoruz: Goose quack struct 'Goose' does not implement all requirements for 'Quackable' required function 'quack' is not implemented Bu tür statik tip kontrolünün saf Python yaklaşımına göre avantajı, hataları kolayca yakalayabilmemiz ve kodun derlenmeyeceği için hataların üretime gönderilmesini önleyebilmemizdir. Miras Mojo'daki özellikler zaten kalıtımı desteklemektedir, dolayısıyla "Quackable" özelliğimiz "Audible" özelliğini şu şekilde genişletebilir: trait Audible: fn make_sound(self): ... trait Quackable(Audible): fn quack(self): ... Bu, yapısının özelliğine uyum sağlamak için hem hem de uygulaması gerektiği anlamına gelir. Duck Quackable quack make_sound Bu, Go'daki "Arayüz yerleştirme" kavramına benzer; burada diğer arayüzlerden miras alan yeni bir arayüz oluşturmak için ana arayüzleri şu şekilde gömebilirsiniz: type Quackable interface { Audible // includes methods of Audible in Quackable's method set } Statik Yöntemler Özellikler ayrıca bir yapının örneğini oluşturmadan çalışan statik yöntemleri de kabul eder: trait Swims: @staticmethod fn swim(): ... @value struct Duck(Quackable, Swims): fn quack(self): print("Quack!") @staticmethod fn swim(): print("Swimming") fn make_it_swim[T: Swims](): T.swim() Bunun gibi statik bir yöntem çağırırsınız: def main(): make_it_quack(Duck()) make_it_quack(Goose()) Duck.swim() Hangisi çıktı verecek: Quack! Honk! Swimming Son yöntem çağrısında Duck örneğinin oluşturulmadığına dikkat edin. Python'daki statik yöntemler bu şekilde çalışır ve nesne yönelimli programlamadan biraz ayrılır. Mojo bu Python işlevselliğini temel alır. Go Arayüzleriyle Karşılaştırıldığında Mojo Özelliklerinin Sınırlamaları İlginç bir şekilde, herhangi bir türün geçişine izin veren ve Go Generics'in tanıtılmasından önce Go topluluğu arasında popüler olan boş arayüzlü Go hilesi , Mojo tipi işleviyle çalışmayacaktır. interface{} fn Yapınız, veya gibi yaşam döngüsü yöntemlerinden en az birini uygulamalıdır; bu durumda, özellik türlerini kabul eden işlevlerle kullanılmak üzere veya ile uyumlu olmasını sağlar. __len__ __str__ Sized Stringable Bu aslında gerçek bir sınırlama değildir ve Mojo'da çok mantıklıdır, çünkü Mojo'da dinamik yazmaya ihtiyacınız varsa, daha esnek olan işlevine geri dönebilir ve ardından bilinmeyenlerle çalışmak için olağan Python büyüsünü uygulayabilirsiniz. türleri. def Daha katı Mojo işlevleri aynı zamanda gibi türleri kullanan genel yapılar üzerinde de çalışır; bununla ilgili daha fazlasını okuyun. fn DynamicVector buradan Gördüğüm diğer bir sınırlama, özelliklerden ziyade yapılarla ve bunların yöntemleriyle ilgilidir ve Temiz Mimarinin uygulanmasının/kodun farklı parçalara ayrılmasının önünde potansiyel bir engeldir. Go vs. Mojo yapı yöntemi tanımına sahip önceki örneklerden birini düşünün: type Duck struct {} func (d Duck) quack() { fmt.Println("Quack!") } @value struct Duck(Quackable): fn quack(self): print("Quack!") Mojo örneği, Python benzeri bir söz dizimini takip ederek, yöntem tanımını doğrudan yapının içine yerleştirir; Go sürümü ise onu yapının kendisinden ayırmasına izin verir. Bu versiyonda eğer çok tür ve metod içeren çok uzun bir yapıya sahipsem, okunması biraz daha zor olacaktır. Ancak bu kritik bir fark değil, sadece dikkat edilmesi gereken bir şey. Mojo özellikleri, dilin ilk günlerinde olmasına rağmen zaten oldukça kullanışlıdır. Go felsefesi tamamen basitliğe odaklanmış ve özellikleri minimumda tutmaya çalışsa da, gelecekte Mojo özelliklerine daha fazla işlevsellik eklendiğini göreceğiz, bu da onları daha da güçlü hale getirecek ve tonlarca farklı kullanım senaryosunu mümkün kılacak.