internet pencereler Android

Rust: Mozilla uzmanlarından yeni bir programlama dili ile başlangıç. Rust dili ve neden yemelisiniz Rust programlamaya nereden başlamalı


"Pas Dilini Eleştirmek ve Neden C/C++ Asla Ölmeyecek" yazısını çok beğendik. Yazara makaleyi İngilizce'ye çevirerek blogumuzda yayınlamamızı önerdik. Kabul etti ve bu makaleyi Rusça ve İngilizce olarak sunmaktan memnuniyet duyuyoruz. Orijinal makale yer almaktadır.

Orijinal makale yayınlanmıştır (Rusça metin). Makale, yazarın onayı ile blogumuzda yayınlanmıştır.

Not: Aşağıda Rust'un hızlı ve güvenli bir dil oluşturma girişimi olduğunu varsayıyorum. Ne de olsa Mozilla'daki adamlar bunu bir tarayıcı motoru geliştirme aracı olarak yaptılar. Bu sadece başka bir güvenli dilse, garipleşiriz. Zaten bir düzine farklı güvenli dil var, herkes beğenisine göre bulacak. Ve amaç C++'ın yerini almak değilse, o zaman (1) güvensiz alt küme neden dilde yapılır? (2) dilden hafif akışları kaldırmak neden uygun oldu? Başka bir deyişle, bu durumda, olan şey hiçbir anlam ifade etmiyor.

Birdenbire linux.org.ru forumunu okursanız, bunun, bu başlıkta tartışılan Rust'ı sevmemek için tamamen teknik 10 nedenin listesi olmadığını unutmayın. Skype tartışması olarak sevgili yoldaş @ sum3rman Bu nedenlerin ne kadar "teknik" olduğu konusunda birden fazla görüş vardır. Genel olarak, bir incir listesi yaptım, ancak ondan bazı noktalar, belki de en ilginç olanı hala alıntı yapmaya cesaret ediyorum. Aslında, gözler için yeterince basit, teknik olmayan nedenler var.

C / C ++ 'ın öngörülebilir gelecekte hiçbir yere gitmeyeceği gerçeği, aklı başında herhangi bir kişi için açıktır. Hiç kimse neredeyse tüm masaüstü uygulamalarını, işletim sistemi çekirdeklerini, derleyicileri, oyun ve tarayıcı motorlarını, sanal makineleri, veritabanlarını, arşivleyicileri, ses ve video kodeklerini, tonlarca başka sish kitaplığını vb. yeniden yazmayacak. Bu çok hızlı, hata ayıklanmış, zamana göre test edilmiş bir koddur. Yeniden yazmak çok, çok pahalı, riskli ve dürüst olmak gerekirse, yalnızca en inatçı Rust "Uman'ın çarpık zihinlerinde mantıklı. C / C ++ programcılarına olan talep çok büyük olmuştur ve olacaktır. uzun zaman.

Tamam, yeni kod yazarken Rust kullanmaya ne dersiniz?

Bunun "daha doğru" C / C ++ yapmak için ilk girişim olmadığını hatırlayalım. D dilini ele alalım, 2001 yılında ortaya çıktı, çok iyi bir dil. Boş pozisyonlar, normal geliştirme araçları veya özellikle olağanüstü başarı öyküleri yok. OpenMW projesi başlangıçta D ile yazılmıştı ve sonra aniden tamamen C++ ile yeniden yazmaya karar verdiler. Geliştiricilerin de kabul ettiği gibi, "harika bir proje, buna katkıda bulunmaktan mutluluk duyarız ama bu aptal D'yi bilmiyoruz ve bilmek istemiyoruz" tarzında çok sayıda mektup aldılar. Wikipedia, D'ye ek olarak, örneğin Vala, Cyclone, Limbo, BitC gibi C++'ı bir dereceye kadar öldürmek için birçok başka girişim olduğunu bildiriyor. Kaç kişi bu tür dilleri duydu bile?

Bence tarihten ders almanın zamanı geldi. En azından ona normal geliştirme araçlarını gösterene, birkaç başarı öyküsü anlatana ve bu dilde yakınlarda yaşayan bir düzine programcıyı gösterene kadar aklı başında tek bir kişi yeni bir dili bir projeye sürüklemez. Programcılar, belki de en genç olanlar hariç, siz onlara normal geliştirme araçlarını (Racer gibi el sanatları değil), birkaç on binlerce hazır kütüphaneyi (değil "deneysel", "kararsız" vb.), birkaç başarı hikayesi anlatmayın ve şehirlerinde bir düzine açık iş yeri gösterin. Tavuk ve yumurta sorunu. Çok nadiren, bu sorun, özellikle bazı büyük şirketlerin (Google, Typesafe) zaman ve para yatırımı nedeniyle başarılı bir şekilde çözülebilir (örneğin, burada örnek olarak Scala verilebilir). , dili popülerleştirmekle ilgileniyor.

Belirttiğim gibi, teknik olmayan nedenler tek başına fazlasıyla yeterli. Ancak, tamamen meraktan, bir an için orada olmadıklarını hayal etmeye çalışalım. O zaman Rust'ta yazmamak için bir sebep yok mu? Bunun da en azından çok büyük bir soru olduğu ortaya çıktı.

C/C++ farklı şeyler için eleştiriliyor. Bu arada, üretimde C++ kodunu bile uzaktan görmemiş olanlar tarafından çok sık eleştiriliyor. Kısaca ve net bir şekilde problem şu şekilde açıklanabilir: C++ çok hızlıdır (ve ayrıca bellek, pil gücü vb. talep etmez), ancak dizilerin sınırlarının ötesine geçmenize izin vermesi anlamında güvenli değildir. , yanlışlıkla boşaltılan bellek parçalarına erişin, vb. Bir zamanlar bu sorun Java, C#, Python ve diğerleri gibi bir yığın güvenli dilin ortaya çıkmasına neden oldu. Ancak bu dillerin C ++ ile karşılaştırıldığında çok kaynak gerektirdiği ve başka dezavantajları olduğu ortaya çıktı, en azından çöp toplama sırasında dünyanın kaçınılmaz durmasını hatırla. Bu nedenle, insanlar dili C ++ kadar hızlı ve aynı zamanda güvenli hale getirme görevi ile mücadele ediyor. Bu dillerden biri de Rust.

Rust gerçekten güvenli, ancak ne yazık ki hızlı olmaktan uzak. Bu yazının yazıldığı sırada hız açısından Rust, Java, Go ve Haskell ile karşılaştırılabilir:

Zamanla bir şekilde hız aşırtılacağını içtenlikle umuyorum, ancak o zamana kadar hız ve güvenlikten ödün verme açısından Scala veya Go'dan çok daha ilginç değil. Şimdiye kadar, bir dili hiç hızlı ve güvenli hale getirmenin mümkün olup olmadığı veya bir dizinin sınırlarının dışında olup olmadığını sürekli kontrol etmenin, C kitaplıklarına bağlamalar etrafında güvenli bağlama vb. C / C++.

Rust aslında nasıl güvenlidir? Basit bir ifadeyle, yerleşik bir statik kod çözümleyicisine sahip bir dildir. C ++ için tipik olan tüm hataları yakalayan gerçekten çok harika bir statik analizör, ayrıca yalnızca bellek yönetimiyle ilgili olanları değil, aynı zamanda çoklu kullanımla ilgili olanları da. Değişken nesnenin bağlantısını kanal üzerinden başka bir iş parçacığına ilettim ve ardından bu bağlantıyı kendim kullanmaya çalıştım - hepsi bu, derlenmeyecek. Bu gerçekten havalı.

Çoğu zaman, kodun yalnızca %10'unun zamanın %90'ında yürütüldüğü tartışılır (ki, anladığım kadarıyla bu tamamen bir başparmak kuralıdır - bu konuda hızlı bir şekilde titiz bir araştırma bulunamamıştır). Bu nedenle, programın çoğu güvenli Rust'ta yazılabilir ve sıcak kodun %10'u güvenli olmayan bir alt kümeye yazılabilir ve mevcut Rust uygulamasının yavaşlığı gerçekten bir sorun değildir. Tamam, ama sonra Rust'a hiç gerek olmadığı ortaya çıkıyor, çünkü kodun %90'ını Go'da ve %10'unu C'de yazabiliyorum. Yalnızca gümüş mermi arayanlar ve gerçeklikten kopmuş kafirler, Rust'u yalnızca programın %100'ünün sanki tek bir dilde yazılabileceği gerekçesiyle kullanacaklardır. Gerçekte bunlar aynı dilin iki lehçesi olsa da, bir grup Java artı C veya Go artı C'den çok da farklı değildir.

Aslında, 10:90 kuralı hala bir yalan. Bu mantığı takip ederek Java'da WebKit'in %90'ını, VirtualBox'ın %90'ını veya GCC'nin %90'ını yeniden yazabilir ve aynı sonucu alabilirsiniz. Açıkçası durum böyle değil. Mesele şu ki, bir dizi programda bu tutum çok farklı değilse bile, o zaman ellerinize dikkat edin. Diyelim ki tüm program güvenli olmayan C / C ++ ile yazılmış ve yürütme süresi göreceli olarak 0.9 * 1 (sıcak kodun küçük bir kısmı) + ​​0.1 * 1 (çok sayıda soğuk kod) = 1. Şimdi. Si'deki eklemelerle güvenli bir dildeki bir programla karşılaştıralım: 0.9 * 1 + 0.1 * 2 = 1.1, geleneksel olarak farkın %10'u. Çok mu yoksa biraz mı? Ölçeğinize bağlı. Google örneğinde, yüzde birkaçı bile milyonlarca dolar tasarruf sağlayabilir ("Kullanım" başlıklı makaledeki 5. paragrafa bakın). Veya bir sonraki güncelleme ile JVM'nin aniden %10 daha fazla kaynak gerektirmeye başladığını hayal edin! Faizin Amerikan parasına aktarılmasından sonra elde edilen rakamda kaç tane sıfır olacağını tahmin etmeye bile korkuyorum! C ve C++ kullanılan görevlerde %10 dofig'dir.

Bir mantra olarak "erken optimizasyon tüm kötülüklerin köküdür" ifadesini tekrarlıyoruz. Ama kelimenin tam anlamıyla, hızlı sıralama yerine her yerde kabarcık sıralama kullanalım. Programın tam olarak bu yerde yavaşlayacağını kesin olarak bilemiyoruz! Daha verimli bir atomu hemen kullanabiliyorsanız, bazı eylemlerin sıradan sayaçlarını aktörlerde veya işlem belleğinde sarmanın anlamı nedir? Ve genel olarak, önemsiz durumlarda, tüm değişkenleri baştan başlatmaya zorlamak, bir sürü ek kontrol yapmak vb. anlamsızdır. Sonunda %10 değil, %2-5 hızlanma elde edelim. Bu da hiç de fena değil, eğer sadece birkaç dakika fazladan düşünmeyi gerektiriyorsa. Ve daha önce öğrendiğimiz gibi, C / C ++ ile çözülen problemlerde bu büyük bir fark olabilir! O zaman kim bir sıcak nokta bulmanın, kodu yeniden yazmanın (muhtemelen çok fazla kod) ve gerçekten daha hızlı olduğunu kanıtlamanın performansı önceden düşünmekten daha kolay olduğunu söyledi?

Hız ve güvenlik arasındaki dengenin yanı sıra, dilin tasarımı hakkında da sorularım var. Özellikle, beş tür işaretçiyle ilgili. Bir yandan, bir programcının değişkenlerin nerede olduğunu, yığında veya yığında olduğunu düşünmesi kötü değildir ve birkaç iş parçacığı onlarla aynı anda çalışabilir veya çalışmayabilir. Ama öte yandan, bir program yazdığınızı ve değişkenin yığında değil, yığında yaşaması gerektiğini hayal edin. Box'ı kullanmak için her şeyi yeniden yazarsınız. Bu nedenle, gerçekten Rc veya Arc'a ihtiyacınız olduğunu anlıyorsunuz. Tekrar yaz. Ve sonra yığındaki sıradan bir değişkenle tekrar üzerine yazarsınız. Bütün bunlar - eldeki normal bir IDE olmadan. Normal sezon da yardımcı olmaz. Peki ya da sadece "Vec" tarzında >>> "Merhaba Java! Ama en üzücü olan şey, derleyicinin tüm değişkenlerin ömrünü zaten bilmesi, tüm bu Kutuları, Yayları vb. otomatik olarak görüntüleyebilmesidir. Ama nedense işin bu kısmı kaldı. val yazmak (üçüncü binyılda!) ve gerektiğinde Box veya R'yi açıkça belirtmek çok daha uygun olurdu.

Bu nedenle, özellikle, Rust'ın kapsamı büyük ölçüde daraltılmıştır. Aklı başında hiç kimse web ve sunucu tarafını böyle bir dilde yazmaz. Özellikle JVM kapsamında aynı dillere göre önemli avantajlar sağlamadığı düşünülürse. Ve Go ile normal hafif iş parçacıkları (gelecekte değil) bu görevler için çok daha çekici görünüyor. Futures ile ayağınıza kurşun sıkmamak için hala çalışmayı öğrenmeniz gerekiyor ve "güvenli dil" diyorsunuz. Evet, bu dillerin kendine has özellikleri var, aynı dünyayı durduruyor, ancak bu sorun hem mikro hizmetlere kesilerek hem de diğer yöntemlerle çözülebilir. Ve evet, hiç kimse Rust'ı JavaScript'e çevirmeyecek, AWS'de mizanpaj için komut dosyaları yazmayacak veya MongoDB için bir sorgu dili olarak kullanmayacak. Android için de pek yazmayacaklar, ancak başka bir nedenden dolayı - birden fazla mimari var, JVM ile çok daha kolay. Birdenbire Rust'ın "tüm görevler için uygun" olduğunu düşündüyseniz, sizi hayal kırıklığına uğratmak zorundayım.

Peki, yığına:

  • Makrolar, normal istisnaların olmamasından kaynaklanan aşırı ayrıntıya bir yedek olarak. Metaprogramlamanın sorunları hakkında zaten yazdım, özellikle bu nedenle Rust için normal bir IDE görmemiz pek mümkün değil. Ve emin değilim ama görünüşe göre Rust'taki makrolarda ad alanları bile yok.
  • İnsanlar aptaldır ve kargo, Crates.io'yu atlayarak paketleri doğrudan git depolarından çekmeyi şiddetle teşvik eder. Sonuç olarak, Rabar'ı ile Erlang dünyasında olduğu gibi paketlerle aynı karmaşayı alma olasılığı yüksektir.Bu arada, Go dünyasında, aynı durum gibi görünüyor.
  • Birçok yeni dil gibi Rust da basitleştirme yolunu izliyor. Genel olarak, neden normal bir miras ve istisna olmadığını anlıyorum, ancak birinin benim için böyle şeylere karar vermesi, tatsız bir tat bırakıyor. C ++, programcıyı neyin kullanıp neyin kullanmayacağı konusunda sınırlamaz.
  • Sadeleştirme yolunu izleyecek olsaydık, o zaman dilin tüm bu uzantılarını atmak zorunda kalırdık. Aksi takdirde Haskell dünyasında olduğu gibi her programcının kendi lehçesinde yazdığı ortaya çıkıyor.
  • Akıllı işaretçiler ücretsiz olmaktan çok uzaktır ve öngörülebilir çöp toplama sürelerine yol açmaz. Bazı iş parçacıkları aniden çok derin bir veri yapısını yayınlama ayrıcalığına sahip oldu. Ölü bağlantıların labirentinde yürürken, ona bağlı olan ipler sabırla donuklaşıyor. Aynı sorun küçük yığınlarıyla Erlang'da da var, ben de bir kereden fazla gözlemledim. Akıllı işaretçilerin kendi sorunları, aynı bellek parçalanması ve sızıntıları vardır. Döngüsel yapıda wikpointer'ı unuttum, hepsi bu. Ve bu güvenli olduğunu iddia eden bir dilde. Tahmin edilebilir bir GC zamanı istiyorsanız, uygulamanızın yük altındaki davranışını inceleyin ve GC zamanı size uymuyorsa harekete geçin (en azından aynı nesne havuzlarını hatırlayın) veya belleği manuel olarak yönetin.
  • Rust semantiğinin katı bir tanımını gören var mı? En azından bir hafıza modeli var mı? Ayrıca benim için programların "doğruluğunu kanıtlayan", kaynak kodunu on farklı şekilde yorumlayabilen "güvenli" bir dil, ha!
  • sana şunu hatırlatmadan edemeyeceğim sorun neredeyse her zaman insanlardadır, teknolojide değil... Aniden yavaşlayan kötü bir C++ veya Java kodu alırsanız, bunun nedeni teknolojinin kötü olması değil, onu doğru şekilde kullanmayı öğrenmemiş olmanızdır. Rust'tan da mutsuz olacaksınız, ancak farklı nedenlerle. Daha popüler araçları kullanmayı öğrenmek ve onları sevmeye başlamak daha kolay değil mi?

Genel olarak, önümüzdeki 5 yıl boyunca Rust'tan ziyade C / C ++ öğrenmeye zaman ayırmam daha iyi olacak. C++ - bu bir endüstri standardıdır... 30 yılı aşkın süredir bu dilde çeşitli problemler başarıyla çözülmüştür. Ve Rust ve onun gibi diğerleri belirsiz bir geleceği olan anlaşılmaz oyuncaklar. En azından 2000'li yıllardan beri C++'ın yakın ölümü hakkında konuşuldu, ancak bu süre zarfında C / C++ ile yazmak daha az olmadı. Tam tersi. Ve dilin geliştiğini görüyoruz (C ++ 11, C ++ 14), bunun için yeni araçlar ortaya çıkıyor (en azından CLion ve Clang'ı unutmayın) ve sadece bir sürü karşılık gelen boş yer var.

Bir C++ programcısı her zaman iyi bir maaşla kolayca bir iş bulabilir ve gerekirse Rust'ı hızla yeniden eğitebilir. Tersi çok, çok şüpheli. Bu arada, dil, eğer varsa, yeni bir iş yeri seçerken tek ve belirleyici bir faktör olmaktan uzaktır. Ek olarak, deneyimli bir C / C ++ programcısı, PostgreSQL veya Linux çekirdek kaynaklarına kolayca girebilir, güçlü modern geliştirme araçlarını kullanabilir ve ayrıca birçok kitap ve makaleyi (örneğin, OpenGL üzerinde) emrinde bulundurabilir.

Zamanınızı ve sağlığınızı koruyun, göründüğü kadar çok yok!

2013 yılında Mozilla, yeni bir Servo web tarayıcı motoru geliştirmek için Samsung ile ortaklık kurdu. Mobil cihazların çok çekirdekli işlemcileri için özel olarak oluşturulmuştur, görevleri paralel iş parçacıklarına bölebilir ve web sayfalarının yükleme süresini önemli ölçüde azaltabilir. Servo tamamen Mozilla'nın mobil uygulamalar yazmak için geliştirdiği Rust programlama dilinde yazılmıştır.

Dil hakkında

Rust, çeşitli kodlama stillerini destekleyen prosedürel bir programlama dilidir. Geliştirici Graydon Hor, dili 2006 yılında oluşturmaya başladı ve Mozilla projeye üç yıl sonra katıldı. 2010 yılında Rust, Mozilla Zirvesi'nde sunuldu. Aynı yıl geliştirme, Rust ile yazılmış bir derleyiciye aktarıldı. Derleyici, veri tabanı olarak LLVM evrensel program analiz ve dönüştürme sistemini kullanmıştır.

Dilin ilk kararlı sürümü 2015 yılında piyasaya sürüldü. Alfa sürümünün yayınlanmasından sonra, Rust değişikliklere uğradı - derleyicinin içinde değişmeyecek yalnızca hazır özellikler kaldı. Diğer her şey deneysel bölüme taşındı.

Dilin kalbine Graydon Khor şu kavramları koydu:

  • Güvenlik. Rust, varsayılan olarak etkinleştirilen bir dizi programcı kısıtlaması içerir. Bunları bloklarda ve işlevlerde devre dışı bırakmak için "güvensiz" etiketi gereklidir.
  • Hız. Dil, programcı için açık bir sayıda avantaj sağlayan başka bir programlama dili C ++ ile hız bakımından karşılaştırılabilir.
  • paralellik. Sistem aynı anda birkaç hesaplama yapabilir, bununla birlikte birbirleriyle etkileşime girebilirler.
  • kısalık. Rust'taki ilk anahtar kelimeler beş karakter uzunluğundaydı. Ancak daha sonra bu kısıtlama kaldırıldı.

İlk Rust kodlarından birine bir örnek

Ancak Rust'ın dezavantajları da yok değil, bunlardan en çarpıcı olanı:

  • Kodun fazlalığı.
  • Dil öğrenimi için literatür eksikliği.
  • Derleme seçeneklerine girmede netlik. Diğer dillerde benzer kurallar olmadığı için bu her zaman deneyimli programcılara uymaz.

Bununla birlikte, dil düzenli olarak güncellenir ve tamamlanır: güncellemeleri her 6 haftada bir yayınlanır.

Rust'ı C++ ile Karşılaştırma

Rust'ın yaratıcıları, geliştiricinin C dilinde çeşitli geliştirmeler yaptığı 1980'lerin başında ortaya çıkan C++'ın halefi olduğunu düşünüyor.Bu nedenle, genç ve hala değişen dili zamanla karşılaştırmaya değer. test edildi.

  • Uzak belleğe erişim. C++'da bir değişkeni silmek bir takım sorunlara neden olabilir. Bunun gibi komplikasyonlar Rust'ta mümkün değildir çünkü hafızayı silmek için herhangi bir komut yoktur. Ardıl derleyici, yazılı kodun bir hata içerdiğini bildirecek ve C++ derleyicisi, sorunu bildirmeden, silinen değerler olmadan sonucu verecektir.
  • Noktalı virgül. Kodunuza fazladan bir noktalı virgül eklemek C++'da bir hataya neden olurken, Rust'ta döngü gövdesi kaşlı ayraçlar içine alınır.
  • Güvenli olmayan kod. Rust, ana kodu güvenli olmayan koddan ayıran bir "güvensiz" etiketine sahiptir. Gelecekte, kodu incelerken bu, güvenlik açıkları aramasını daraltmanıza olanak tanır.

Firefox'un uygulandığı yer C ++ idi: bu kaprisli dil, ayrıntılara daha fazla dikkat edilmesini gerektiriyordu. Aksi takdirde, hatalar ciddi güvenlik açıklarına dönüştü. Rust, bu sorunu çözmek için tasarlandı.

Perspektifler

Mozilla'nın programlama dili, Q3 2018 RedMonk sıralamasında sürekli olarak 23. sırada yer alıyor. Uzmanlar, pozisyonunu iyileştirme tehlikesi olmadığına inanıyor. Ne olursa olsun, Ağustos 2018'de, içerik oluşturucular güncellenmiş Rust 1.28'i yayınladı.

Stack Overflow'a göre Rust 2015'te piyasaya sürüldükten sonra geliştiricilerin %74'ü onu görmek istedi. Ancak 2016'da ilk sıraya yerleşti: Kullanıcıların %79'u Rust'u en sevdikleri programlama dili olarak adlandırdı ve onunla çalışmaya devam etme arzusunu dile getirdi. Rust, 2018 yılında da bu parametrede ilk sırayı aldı.

Stack Overflow, 2008 yılında geliştirilen popüler bir kodlama soru-cevap sistemidir.

Rust'ın popülaritesi, geliştirmelerinde onu kullanan şirketlerin sayısıyla doğrulanır. Listede şu anda 105 kuruluş yer alıyor.



Bugün, Rust sözdizimi, derleyiciyle birlikte sağlanan sözdizimi dosyaları kullanılarak vim ve emacs'ta desteklenmektedir.
Ayrıca popüler tescilli Sublime Text 2 editörü ve ücretsiz Kate editörü için sözdizimi paketleri de bulunmaktadır. IDE'de henüz Rust desteği yok. Hata ayıklayıcı desteği de eksik görünüyor.

rustc derleyicisi ile birlikte aşağıdaki yardımcı programlar sağlanır:
> rustdoc- Doxygen gibi kaynak kodlardan otomatik belge üretimi için yardımcı program;
> rustpkg- ek paketleri ve kitaplıkları kolayca kurmanıza izin veren bir paket yöneticisi;
> rusti- sözde REPL yardımcı programı (okuma-değerlendirme-baskı-döngüsü). Özünde, komut satırından bir Rust ifadesini alan, onu dahili LLVM temsiline derleyen, yürüten ve sonucu veren bir test yorumlayıcısıdır;
> pas- parametrelere bağlı olarak diğer yardımcı programları veya derleyiciyi başlatan evrensel bir yardımcı program. Benim için hiç işe yaramadı.

Mevcut tüm dil belgeleri resmi web sitesi www.rust-lang.org'da toplanmıştır. Ayrıntılı bir kılavuz (http://static.rust-lang.org/doc/tutorial.html) vardır - sözdiziminin tüm nüansları, bellek modeli, çalışma zamanı sistemi vb. hakkında kapsamlı resmi belgeler ve ayrıca yerleşik çekirdek kitaplık ve standart kitaplık std. Tüm belgeler İngilizce'dir. Rusça'da ilgili materyal yok ve birkaç mevcut inceleme makalesi zaten çok eski hale geldi.

İdeoloji ve sözdizimi


Rust, kod bloklarını işaretlemek için küme parantezleri kullanan C benzeri bir dildir. Dil "çoklu paradigma"dır, yani. yordamsal, nesne yönelimli, eşzamanlı veya işlevsel bir şekilde kod yazmanıza olanak tanır. Rust, desteklenen herhangi bir platformda yerel ikili dosyaları derler (arka uç olarak LLVM kullanır). Teorik olarak Rust kodu, C/C++ kodu kadar hızlı olmalıdır. Rust, bir sistem dili olarak pazarlanmaktadır, ancak "gerçek" sistem dilleri C, C ++ veya D'de olduğu gibi montaj kodu blokları için yerleşik desteğe sahip değildir.

Rust'ın bellek modeli, doğal olarak boş veya sarkan işaretçilere ve arabellek taşmalarına izin vermez. Yalnızca tek bir kod dizisi içinde çalışan isteğe bağlı bir çöp toplayıcı vardır. Dil, hafif çoklu görev ve iş parçacığından iş parçacığına mesajlaşma için yerleşik desteğe sahiptir. Rust'ta paylaşılan bellek yok. Tüm değişkenler, yığın değişkenlerine, belirli bir iş parçacığı için yığın değişkenlerine ve tüm iş parçacıkları tarafından okunabilen ancak değiştirilemeyen "değişim" yığın değişkenlerine bölünmüştür. Bu, çok iş parçacıklı programlamanın belası olarak kabul edilen kilitlenmeleri otomatik olarak ortadan kaldırır. Dilin ABI'si C ile uyumludur, bu nedenle Rust programları ek sarmalayıcılar olmadan C ile yazılmış kitaplıklara bağlanabilir. Düşük seviyeli sistem programlama ihtiyaçları için ve C ile uyumluluğu sağlamak için, dilin işaretçilerin doğruluğunu kontrol etmeden özel bir "güvensiz" modu vardır. İdeolojisi açısından Rust, Go diline en yakın olanıdır. Tıpkı Go'da olduğu gibi, ana vurgu, çok iş parçacıklı programlamanın basitliği ve büyük ölçekli uygulamalar geliştirme hızı üzerindedir ve sözdizimi bazı yerlerde olağandışı ve biraz şaşırtıcıdır. Aynı zamanda Rust, Go kadar minimalist değil ve bir sistem dili olduğunu iddia ediyor.

Rust'ın sözdizimi, Go, C#, Haskell, Python ve Ruby'den bir kaç fikirle, büyük ölçüde C ve C++'dan ödünç alınmıştır. Dilin sözdizimini ayrıntılı olarak açıklamayacağım, sadece en ilginç kavramlara odaklanacağım.

Pas Mozilla tarafından geliştirilen yeni bir deneysel programlama dilidir. Dil derlenmiş ve çok paradigmalıdır, rekabet için çok fazla yarışmacı olmadığı için kendi içinde ilginç olan C / C ++'a alternatif olarak konumlandırılmıştır. Walter Bright'ın D'sini veya Google'ın Go'sunu düşünün.
Rust, işlevsel, paralel, prosedürel ve nesne yönelimli programlamayı destekler, yani. uygulamalı programlamada fiilen kullanılan neredeyse tüm paradigmalar.

Belgeleri tercüme etmeyi düşünmüyorum (ayrıca, dilin henüz resmi bir sürümü olmadığı için çok az ve sürekli değişiyor), bunun yerine dilin en ilginç özelliklerini vurgulamak istiyorum. Bilgiler hem resmi belgelerden hem de İnternet'teki dilin çok az sözünden toplanmıştır.

İlk izlenim

Dilin sözdizimi geleneksel C-benzeri tarzda inşa edilmiştir (bu iyi bir haberdir, çünkü bu zaten fiili bir standarttır). Doğal olarak iyi bilinen C/C++ tasarım hataları dikkate alınmıştır.
Geleneksel Merhaba Dünya şöyle görünür:
std'yi kullanın; fn main (args :) (std :: io :: println ("merhaba dünya" + args + "!");)

Bir örnek biraz daha karmaşıktır - faktöriyel hesaplama işlevi:

Fn fac (n: int) -> int (let sonuç = 1, i = 1; while i<= n { result *= i; i += 1; } ret result; }

Örnekte görebileceğiniz gibi, işlevler "işlevsel" stilde bildirilir (bu stilin geleneksel "int fac (int n)"ye göre bazı avantajları vardır). Görürüz otomatik tür çıkarımı(let anahtar kelime), argümanda parantez bulunmazken (Go'ya benzer). Anahtar kelimelerin kompaktlığı da hemen belli oluyor. Rust'ın yaratıcıları gerçekten de tüm anahtar kelimeleri olabildiğince kısa tuttular ve dürüst olmak gerekirse buna bayıldım.

Küçük ama ilginç sözdizimsel özellikler

  • Sayısal sabitlerde alt çizgi kullanabilirsiniz. Kullanışlı bir şey, şimdi bu özellik birçok yeni dile ekleniyor.
    0xffff_ffff_ffff_ffff_ffff_ffff
  • İkili sabitler. Tabii ki, gerçek bir programcı kafasında bin'i hex'e çevirmelidir, ancak bu daha uygundur! 0b1111_1111_1001_0000
  • Herhangi bir operatörün gövdeleri (tek bir ifadeden oluşanlar bile) kaşlı ayraçlar içine alınmalıdır. Örneğin, C'de if (x> 0) foo(); , Rust'ta foo () etrafına küme parantezleri koymalısınız
  • Ancak if, while ve benzeri operatörlerin argümanlarının parantez içine alınması gerekmez.
  • çoğu durumda kod blokları ifadeler olarak düşünülebilir. Özellikle, bu örneğin mümkündür:
    let x = if the_stars_align () (4) else if if_else () (3) başka (0);
  • işlevleri bildirmek için sözdizimi - önce fn anahtar sözcüğü, ardından bağımsız değişkenler listesi, bağımsız değişkenin türü adından sonra belirtilir, ardından işlev bir değer döndürürse "->" oku ve dönüş değerinin türü
  • değişkenler benzer şekilde bildirilir: let anahtar sözcüğü, değişkenin adı, değişkenden sonra iki nokta üst üste ile türü belirtebilir ve ardından bir başlangıç ​​değeri atayabilirsiniz.
    sayalım: int = 5;
  • varsayılan olarak tüm değişkenler değişmezdir; mutable anahtar sözcüğü, değişken değişkenleri bildirmek için kullanılır.
  • temel tür adları, karşılaştığım en kompakt adlardır: i8, i16, i32, i64, u8, u16, u32, u64, f32, f64
  • yukarıda belirtildiği gibi, otomatik tür çıkarımı desteklenir
Dil, programlarda hata ayıklamak için yerleşik araçlara sahiptir:
Anahtar kelime hata mevcut süreci sonlandırır
Anahtar kelime kayıt herhangi bir dil ifadesini günlüğe çıkarır (örneğin, stderr'e)
Anahtar kelime iddia etmek ifadeyi kontrol eder ve yanlışsa mevcut işlemden çıkar
Anahtar kelime Not sürecin anormal bir şekilde sonlandırılması durumunda ek bilgileri görüntülemenize olanak tanır.

Veri tipleri

Rust, Go gibi destekler yapısal tipleme(yazarlara göre, diller bağımsız olarak gelişse de, bu onların ortak öncüllerinin etkisidir - Alef, Limbo, vb.). Yapısal tipleme nedir? Örneğin, bir dosyada (veya Rust terminolojisinde "kayıt") bildirilmiş bir yapınız var.
nokta yazın = (x: kayan nokta, y: kayan nokta);
"Nokta" argüman türleri ile bir grup değişken ve fonksiyon bildirebilirsiniz. Ardından, başka bir yerde, örneğin başka bir yapı bildirebilirsiniz.
MySuperPoint yazın = (x: kayan nokta, y: kayan nokta);
ve bu türdeki değişkenler, nokta türündeki değişkenlerle tamamen uyumlu olacaktır.

Buna karşılık, C, C ++, C # ve Java'da kullanılan yalın tipleme bu tür yapılara izin vermez. Nominal yazımla, her yapı, varsayılan olarak diğer türlerle uyumlu olmayan benzersiz bir türdür.

Rust'taki yapılara "kayıtlar" denir. Tuple'lar da vardır - bunlar aynı kayıtlardır, ancak adsız alanlara sahiptir. Bir kaydın öğelerinden farklı olarak, bir demetin öğeleri değiştirilemez.

Vektörler vardır - bazı yönlerden sıradan dizilere benzer ve bazı yönlerden - stl'den std :: vektör tipi. Bir liste ile başlatılırken, C/C++'daki gibi küme parantezleri değil, köşeli parantezler kullanılır.

myvec =;

Bununla birlikte bir vektör, dinamik bir veri yapısıdır, özellikle vektörler birleştirmeyi destekler.

v olsun: değişken =; v + =;

Şablonlar var. Sözdizimleri, C ++'dan gelen "şablon" karmaşası olmadan oldukça mantıklıdır. İşlev şablonları ve veri türleri desteklenir.

Fn for_rev (v: [T], act: blok (T)) (let i = std :: vec :: len (v); while i> 0u (i - = 1u; act (v [i]);)) tip dairesel_buf = (başlangıç: uint, bitiş: uint, buf:);

Dil sözde destekler etiketler... Bu, ek bir alana sahip C'den bir birleşmeden başka bir şey değildir - kullanılan varyantın kodu (yani, birleşme ve numaralandırma arasında ortak olan bir şey). Veya teorik olarak cebirsel bir veri türü.

Etiket şekli (daire (nokta, kayan nokta); dikdörtgen (nokta, nokta);)

En basit durumda, bir etiket bir numaralandırma ile aynıdır:

Etiket hayvan (köpek; kedi;) izin ver a: hayvan = köpek; bir = kedi;
Daha karmaşık durumlarda, "numaralandırmanın" her bir öğesi, kendi "yapıcısı" olan bağımsız bir yapıdır.
Bir başka ilginç örnek, "liste" türünde bir nesneyi tanımlayan özyinelemeli bir yapıdır:
etiket listesi (sıfır; eksiler (T, @liste) ); ) izin ver: liste = eksileri (10, @eksileri (12, @nil));
Etiketler, oldukça karmaşık olabilen kalıp eşleştirme ifadelerine katılabilir.
alt x (eksileri (a, @eksileri (b, _)) (işlem_çifti (a, b);) eksileri (10, _) (işlem_ten ();) _ (başarısız;))

desen eşleştirme

Başlangıç ​​olarak, eşleştirme modelini geliştirilmiş bir anahtar olarak düşünebilirsiniz. Alt anahtar sözcüğü, ardından analiz edilen ifade ve ardından operatörün gövdesinde - kalıplarla eşleşme durumunda kalıplar ve eylemler kullanılır.
alt my_number (0 (std :: io :: println ("sıfır"));) 1 | 2 (std :: io :: println ("bir veya iki");) 3 ila 10 (std :: io :: println ("üç ila on");) _ (std :: io :: println ("başka bir şey");))
"Desen" olarak yalnızca sabitleri (C'deki gibi) değil, aynı zamanda daha karmaşık ifadeleri de kullanabilirsiniz - değişkenler, demetler, aralıklar, türler, yer tutucular ("_"). Modelin hemen ardından gelen while yan tümcesini kullanarak ek koşullar yazabilirsiniz. Tür eşleştirme için operatörün özel bir çeşidi vardır. Bu mümkündür çünkü dilin evrensel bir varyant türü vardır. herhangi nesneleri herhangi bir türden değer içerebilir.

İşaretçiler. Her zamanki "cic" işaretçilerine ek olarak Rust, yerleşik referans sayımına sahip özel akıllı işaretçileri destekler - Paylaşılan kutular ve Benzersiz kutular. C ++ 'dan share_ptr ve unique_ptr ile biraz benzerler. Kendi sözdizimlerine sahiptirler: @ paylaşımlı ve ~ benzersiz. Benzersiz işaretçiler için kopyalama yerine özel bir işlem vardır - hareket ettirin:
x = ~ 10 olsun; izin ver<- x;
böyle bir hareketten sonra x işaretçisi sıfırlanır.

Kapanışlar, kısmi uygulama, yineleyiciler

Fonksiyonel programlamanın başladığı yer burasıdır. Rust, üst düzey işlevler kavramını - yani bağımsız değişkenleri olarak alabilen ve diğer işlevleri döndürebilen işlevler - kavramını tamamen destekler.

1. Anahtar Kelime lambda iç içe bir işlev veya işlevsel veri türü bildirmek için kullanılır.

Fn make_plus_function (x: int) -> lambda (int) -> int (lambda (y: int) -> int (x + y)) let plus_two = make_plus_function (2); iddia plus_two (3) == 5;

Bu örnekte, int türünde bir "x" bağımsız değişkenini alan ve "int-> int" türünde bir işlev döndüren bir make_plus_ işlevine sahibiz (burada lambda bir anahtar kelimedir). İşlevin gövdesi bu işlevi açıklar. "Dönüş" operatörünün olmaması biraz kafa karıştırıcıdır, ancak FP için bu yaygın bir şeydir.

2. Anahtar Kelime engellemek bir işlev türü bildirmek için kullanılır - normal kod bloğuna benzer bir şeyle değiştirilebilecek bir işlev argümanı.
fn map_int (f: blok (int) -> int, vec:) -> (let sonuç =; vec'de i için (sonuç + =;) ret sonucu;) map_int ((| x | x + 1),);

Burada girdi olarak bir bloğu olan bir fonksiyonumuz var - aslında, "int-> int" tipinde bir lambda fonksiyonu ve int tipinde bir vektör (daha sonra vektörlerin sözdizimi hakkında daha fazla bilgi). Çağıran koddaki "blok"un kendisi biraz alışılmadık bir sözdizimi (| x | x + 1) kullanılarak yazılmıştır. Şahsen, C# lambdas'ı daha çok seviyorum, | inatla bitsel OR olarak algılanır (bu arada, tüm eski C işlemleri gibi Rust'ta da bulunur).

3. Kısmi uygulama, bu diğer fonksiyonun bazı argümanlarının değerlerini belirterek çok sayıda argümana sahip başka bir fonksiyona dayalı bir fonksiyon oluşturulmasıdır. Bunun için anahtar kelime kullanılır. bağlamak ve yer tutucu "_":

Let daynum = bind std :: vec :: konum (_, ["mo", "tu", "biz", "do", "fr", "sa", "su"])

Daha açık hale getirmek için, bunun basit bir sarmalayıcı oluşturarak düz C'de yapılabileceğini hemen söyleyeceğim, şöyle bir şey:
const char * daynum (int i) (const char * s = ("mo", "tu", "biz", "do", "fr", "sa", "su"); dönüş s [i]; )

Ancak kısmi uygulama, prosedürel değil, işlevsel bir stildir (bu arada, yukarıdaki örnekte, argümansız bir işlev elde etmek için kısmi bir uygulamanın nasıl yapılacağı açık değildir)

Başka bir örnek: add işlevi, bir int döndüren iki int bağımsız değişkeni ile bildirilir. Ardından, bir int bağımsız değişkeni olan ve bir int döndüren işlev tipi single_param_fn bildirilir. Bağlama kullanılarak, kısmi bağımsız değişkenlere sahip olan add işlevinin üzerine inşa edilen iki işlev nesnesi, add4 ve add5 bildirilir.

Fn ekle (x: int, y: int) -> int (ret x + y;) type single_param_fn = fn (int) -> int; add4'e izin ver: single_param_fn = ekle ekle (4, _); izin ekle5: single_param_fn = ekle ekle (_, 5);

İşlevsel nesneler, normal işlevlerle aynı şekilde çağrılabilir.
iddia (topla (4,5) == ekle4 (5)); iddia (topla (4,5) == ekle5 (4));

4. Saf fonksiyonlar ve yüklemler
Saf işlevler, yan etkisi olmayan işlevlerdir (saf işlevler dışında herhangi bir işlevi çağırmayanlar dahil). Bu tür işlevler, saf anahtar sözcüğü ile ayırt edilir.
saf fn lt_42 (x: int) -> bool (ret (x)< 42); }
Tahminler, bir bool türü döndüren saf işlevlerdir. Bu tür işlevler typestate sisteminde kullanılabilir (aşağıya bakın), yani derleme zamanında çeşitli statik kontroller için çağrılabilirler.

Sözdizimi makroları
Planlanan özellik, ancak çok kullanışlı. Rust'ta hala geliştirmenin ilk aşamalarında.
std :: io :: println (#fmt ("% s, % d'dir", "cevap", 42));
printf'e benzer, ancak derleme zamanında çalıştırılan bir ifade (buna göre, tüm argüman hataları derleme zamanında algılanır). Ne yazık ki, sözdizimsel makrolar hakkında çok az materyal var ve kendileri de geliştirme aşamasındalar, ancak Nemerle makroları gibi bir şeyin ortaya çıkacağına dair bir umut var.
Bu arada, aynı Nemerle'den farklı olarak, # sembolünü kullanarak makroları sözdizimsel olarak vurgulama kararının çok yetkin olduğunu düşünüyorum: bir makro, bir işlevden çok farklı bir varlıktır ve bir bakışta nerede olduğunu görmenin önemli olduğunu düşünüyorum. işlevler kodda çağrılır ve nerede - makrolar.

Öznitellikler

C# özniteliklerine benzer bir kavram (ve hatta benzer sözdizimi ile). Bunun için geliştiricilere özel teşekkürler. Tahmin edebileceğiniz gibi, öznitelikler, açıklama ekledikleri varlığa meta bilgiler ekler.
# fn register_win_service () (/ * ... * /)
Öznitelik sözdiziminin başka bir varyantı icat edildi - aynı satır, ancak sonunda noktalı virgül ile mevcut bağlamı açıklar. Yani, böyle bir özniteliği kapsayan en yakın kaşlı ayraçlarla eşleşen her şey.
fn register_win_service () (#; / * ... * /)

paralel hesaplama

Belki de dilin en ilginç kısımlarından biri. Aynı zamanda, şu anda öğreticide hiç anlatılmıyor :)
Bir Rust programı bir "görev ağacından" oluşur. Her görevin bir giriş işlevi, kendi yığını, diğer görevlerle etkileşim araçları - giden bilgiler için kanallar ve gelenler için bağlantı noktaları vardır ve dinamik yığındaki nesnelerin bir kısmına sahiptir.
Birçok Rust görevi, tek bir işletim sistemi işleminde bulunabilir. Pas görevleri "hafiftir": her görev, bir işletim sistemi işleminden daha az bellek tüketir ve bunlar arasında geçiş yapmak, işletim sistemi işlemleri arasında geçiş yapmaktan daha hızlıdır (bu muhtemelen "iş parçacığı" anlamına gelir).

Görev, bağımsız değişken içermeyen en az bir işlevden oluşur. Görev, spawn işlevi kullanılarak başlatılır. Her görevin, bilgileri diğer görevlere ilettiği kanallar olabilir. Kanal, kanal veri türü tarafından parametrelendirilen özel bir şablon türü chan'dir. Örneğin, chan, imzasız baytları aktarmak için bir kanaldır.
Bir kanala göndermek için, ilk argümanı kanal, ikincisi ise gönderilecek değer olan send işlevini kullanın. Aslında bu işlev, değeri kanalın dahili ara belleğine yerleştirir.
Portlar veri almak için kullanılır. Bağlantı noktası, bağlantı noktası veri türü tarafından parametrelendirilen şablonlu bir bağlantı noktası türüdür: bağlantı noktası, imzasız baytları almak için kullanılan bağlantı noktasıdır.
Bağlantı noktalarından okumak için, argümanı bağlantı noktası olan recv işlevi kullanılır ve dönüş değeri bağlantı noktasından gelen verilerdir. Okuma görevi engeller, yani. bağlantı noktası boşsa, başka bir görev bağlantı noktasıyla ilişkili kanalda veri gönderene kadar görev bekleme durumuna geçer.
Kanalları bağlantı noktalarına bağlamak çok basittir - chan anahtar sözcüğünü kullanarak bir bağlantı noktasına sahip bir kanalı başlatarak:
let reqport = bağlantı noktası ();
let reqchan = chan (reqport);
Bir bağlantı noktasına birden çok kanal bağlanabilir, ancak tersi olamaz - bir kanal aynı anda birden çok bağlantı noktasına bağlanamaz.

Yazı durumu

“Typestate” kavramının Rusça'ya genel olarak kabul edilmiş bir çevirisini bulamadım, bu yüzden ona “type state” diyeceğim. Bu özelliğin özü, statik yazımda kabul edilen olağan tür denetimine ek olarak, derleme aşamasında ek bağlam denetimlerinin de mümkün olmasıdır.
Şu veya bu şekilde, türlerin durumları tüm programcılara aşinadır - derleyicinin mesajlarına göre, "değişken başlatma olmadan kullanılır." Derleyici, hiç yazılmamış bir değişkenin okuma için kullanıldığı yerleri belirler ve bir uyarı verir. Daha genel olarak, bu fikir şöyle görünür: her nesnenin alabileceği bir dizi durum vardır. Her durumda, bu nesne için geçerli ve geçersiz işlemler tanımlanır. Derleyici, programdaki belirli bir yerde bir nesne üzerinde belirli bir işleme izin verilip verilmediğini kontrol edebilir. Bu kontrollerin derleme zamanında yapılması önemlidir.

Örneğin, "dosya" türünde bir nesnemiz varsa, "kapalı" ve "açık" durumuna sahip olabilir. Ve dosya kapatılırsa dosyadan okuma işlemi geçersizdir. Modern dillerde, bir okuma işlevinin bir istisna atması veya bir hata kodu döndürmesi yaygındır. Tür durumu sistemi derleme zamanında böyle bir hatayı algılayabilir - tıpkı derleyicinin bir değişkenin okuma işleminin olası herhangi bir yazma işleminden önce gerçekleştiğini belirlemesi gibi, "dosya açık" durumunda geçerli olan "Okuma" yönteminin de geçerli olduğunu belirleyebilir. , nesneyi bu duruma aktaran "Aç" yönteminden önce çağrılır.

Rust'ta "yüklemler" kavramı vardır - yan etkisi olmayan ve bir bool türü döndüren özel işlevler. Bu tür işlevler, belirli koşulları statik olarak kontrol etmek amacıyla derleme zamanında çağrılacak derleyici tarafından kullanılabilir.

Kısıtlamalar, derleme zamanında gerçekleştirilebilen özel kontrollerdir. Bunun için check anahtar sözcüğü kullanılır.
saf fn is_less_than (int a, int b) -< bool { ret a < b; } fn test() { let x: int = 10; let y: int = 20; check is_less_than(x,y); }
Tahminler, işlevlerin giriş parametrelerine aşağıdaki şekilde "asılabilir":
fn testi (int x, int y): is_less_than (x, y) (...)

Typestate hakkında çok az bilgi var, pek çok nokta hala belirsiz, ancak konsept yine de ilginç.

Bu kadar. Bazı ilginç noktaları kaçırmış olabilirim, ancak makale zaten şişirildi. İsterseniz şimdi Rust derleyicisini kurabilir ve çeşitli örneklerle oynamayı deneyebilirsiniz. Montaj bilgileri için bkz.

Rust'ta yeniyim ama hızla en sevdiğim programlama dili haline geliyor. Rust'ta küçük projeler yazmak genellikle daha az ergonomik ve daha fazla zaman alırken (en azından direksiyon başındayken), program tasarımı hakkında düşünme biçimimi zorluyor. Yeni bir şey öğrendikten sonra derleyiciyle olan savaşlarım daha az sıklaşıyor.

Rust topluluğu son zamanlarda çabalarının çoğunu Tokio kütüphanesi olarak uygulanan asenkron G/Ç'ye odakladı. Ve bu harika.

Web sunucuları ve ilgili şeylerle çalışmamış olan topluluk üyelerinin çoğu, neyi başarmak istediğimiz konusunda net değiller. 1.0 çağında bunlar tartışılırken ben de daha önce hiç çalışmadığım için bu konuda belirsiz bir fikrim vardı.

  • Ne olduğunu - Zaman uyumsuz G / Ç?
  • eşyordamlar nelerdir ( eşyordamlar )?
  • Hafif akışlar nelerdir ( hafif iplikler )?
  • Gelecek nedir? ( gelecekler )?

  • Birbirlerine nasıl uyuyorlar?

Size kaseti indiren küçük bir programın nasıl yazılacağını göstereceğim ( beslemek) JSON biçiminde, not listesini ayrıştırır ve biçimlendirilmiş biçimde konsola çıkarır.

Her şey çok özlü bir kodla sonuçlandı. Nasıl? Kesimin altına bakın.

Unsafe anahtar sözcüğü, Rust dilinin tasarımının ayrılmaz bir parçasıdır. Buna aşina olmayanlar için: güvensiz, basit bir ifadeyle, tür denetimini atlamanın bir yolu olan bir anahtar kelimedir ( tip kontrolü) Pas.

Güvenli olmayan anahtar kelimenin varlığı, başlangıçta birçokları için bir sürprizdir. Gerçekten de programların bellek hatalarından çökmemesi Rust'ın bir özelliği değil mi? Eğer öyleyse, tip sistemini atlamanın neden kolay bir yolu var? Bu, dilde bir tasarım hatası gibi görünebilir.

Yine de güvensizlik bence bir dezavantaj değil. Aslında, dilin önemli bir parçasıdır. güvensiz bir tür çıkış valfi gibi davranır - bu, tip sistemini basit durumlarda kullanabileceğimiz anlamına gelir, ancak kodunuzda kullanmak istediğiniz her türlü zor numarayı kullanmamıza izin verir. Yalnızca güvenli olmayan kodunuzu güvenli harici soyutlamaların arkasına saklamanızı istiyoruz.

Bu not, güvenli olmayan anahtar kelimeyi ve sınırlı "güvensizlik" fikrini tanıtmaktadır. Aslında bu biraz sonra yazmayı umduğum bir notun habercisi. Güvenli olmayan kodda nelerin yapılıp nelerin yapılamayacağını belirleyen Rust bellek modelini tartışıyor.

Rust'a yeni başlayan biri olarak, dizeleri temsil etmenin farklı yolları konusunda kafam karıştı. Rust kitabında, örneklerde üç farklı türde dize değişkeni kullanan "Başvurular ve Ödünç Alma" adlı bir bölüm vardır: String, & String ve & str.

str ve String arasındaki farkla başlayalım: String, genişletilebilir, yığınla ayrılmış bir veri yapısıdır, str ise değişmez, sabit uzunluklu bir dizedir. bir yerde akılda.

Birçok programcı, nesne yönelimli dillerde nasıl programlanacağını zaten biliyor. Rust, klasik bir nesne yönelimli dil değildir, ancak temel OOP araçları içinde uygulanabilir.

Bu yazıda, Rust'ta OOP tarzında nasıl programlanacağına bir göz atacağız. Bunu bir örnek kullanarak yapacağız: bir eğitim probleminde bir sınıf hiyerarşisi oluşturacağız.

Görevimiz geometrik şekillerle çalışmak. Bunları metin biçiminde görüntüleyeceğiz ve alanlarını hesaplayacağız. Şekil setimiz - dikdörtgen, kare, elips, daire.

Rust, diğer birçok popüler dilden biraz farklı olan zarif bir dildir. Örneğin, sınıfları ve kalıtımı kullanmak yerine Rust, kendi özellik tabanlı tip sistemini sunar. Ancak, birçok yeni Rust programcısının (kendim gibi) kabul edilen tasarım modellerine aşina olmadığına inanıyorum.

Bu yazıda tasarım desenini tartışmak istiyorum yeni tip(newtype) ve tür dönüştürmeye yardımcı olan From ve Into özellikleri.

Son zamanlarda programlamada kullandığımız tasarım kalıpları ve teknikleri hakkında çok düşünüyorum. Bir projeyi araştırmaya başlamak ve bir kereden fazla karşılaştığınız tanıdık kalıpları ve stilleri görmek gerçekten harika. Bu, projenin anlaşılmasını kolaylaştırır ve işi hızlandırmayı mümkün kılar.

Bazen yeni bir proje üzerinde çalışıyorsunuz ve bir önceki projede yaptığınız gibi bir şey yapmanız gerektiğini fark ediyorsunuz. İşlevselliğin veya bir kitaplığın parçası olmayabilir, şık bir makro veya küçük bir kap içine sığdırılamayan bir şey olabilir. Sorunu iyi çözen sadece bir tasarım deseni veya yapısal konsept olabilir.

Bu tür problemlere sıklıkla uygulanan ilginç bir model "Durum Makinesi"dir. Bu ifadenin tam olarak ne anlama geldiğini ve neden bu kadar ilginç olduğunu anlamak için biraz zaman ayırmayı öneriyorum.

Aşağıda, Rust programlama dilinde taşıma, kopyalama ve ödünç almanın grafiksel bir açıklaması bulunmaktadır. Temel olarak, bu kavramlar yalnızca Rust'a özgüdür ve genellikle yeni başlayanlar için bir engeldir.

Karışıklığı önlemek için metni minimumda tutmaya çalıştım. Bu not, çeşitli öğreticilerin yerini tutmaz ve yalnızca bilginin görsel olarak daha kolay algılandığına inananlar için hazırlanmıştır. Rust'ı yeni öğrenmeye başladıysanız ve bu grafikleri faydalı buluyorsanız, kavramları daha iyi sağlamlaştırmak için kodunuzu benzer şemalarla işaretlemenizi tavsiye ederim.

Peano sayılarını kullanarak doğal sayıların aritmetiğini uygulamak, programlama öğreniminde popüler bir problemdir. Bunları Rust'ta uygulamanın mümkün olup olmadığını merak ediyordum.

Böylece benim görevim, tip kontrolü ile doğal sayıları yazmak ve eklemek.

Wikipedia'ya göre "Peano'nun aksiyomları, 19. yüzyılda İtalyan matematikçi Giuseppe Peano tarafından tanıtılan doğal sayılar için aksiyom sistemlerinden biridir."

Doğal sayıları girebileceğiniz ve kullanabileceğiniz iki tanesiyle ilgileniyoruz:

  • 1 bir doğal sayıdır
  • Doğaldan sonraki sayı da doğaldır.

Paslanmak için kelimesi kelimesine yazalım:

1 2 3 4 enum Nat (Sıfır, Succ (Nat))

Nat ya sıfırdır ya da bir sonraki doğal sayıdır.

Yorum Yap: futures-rs projesi yeniden düzenlendi ve birçok şey yeniden adlandırıldı. Linkler mümkünse güncellendi.

Futures'a Başlarken

Bu belge, vadeli işlemlerin ve akışların sıfır maliyetli uygulamalarını sağlayan Rust programlama dili kapsayıcısını, vadeli işlemleri keşfetmenize yardımcı olacaktır. Vadeli işlemler C++, Java ve Scala gibi diğer birçok programlama dilinde mevcuttur ve vadeli işlem kapsayıcısı bu dillerin kitaplıklarından ilham alır. Bununla birlikte, ergonomiktir ve Rust'ın doğasında bulunan sıfır maliyetli soyutlama felsefesine, yani gelecek oluşturma ve oluşturmanın bellek tahsisi gerektirmediği ve bunları yöneten Görev için yalnızca bir tahsisin gerekli olduğu felsefesine bağlıdır. Vadeli işlemler, Rust'ın eşzamansız birleştirilebilir yüksek performanslı G/Ç'sinin omurgası olmalıdır ve ilk karşılaştırmalar, vadeli işlemler üzerine kurulu basit bir HTTP sunucusunun gerçekten hızlı olduğunu gösteriyor.

Bu belgeler birkaç bölüme ayrılmıştır:

  • "Selam Dünya!";
  • gelecek tip;
  • Akış özelliği;
  • belirli gelecekler ve akış;
  • vadeli dönüş;
  • Görev ve gelecek;
  • yerel görev verileri.

Yorum Yap: futures-rs projesi yeniden düzenlendi ve birçok şey yeniden adlandırıldı. Linkler mümkünse güncellendi.

Rust ekosistemindeki en büyük boşluklardan biri hızlı ve verimliydi asenkron G / Ç... mio kitaplığından sağlam bir temele sahibiz, ancak çok düşük seviyeli: durum makinelerini manuel olarak oluşturmamız ve geri aramaları dengelememiz gerekiyor.

Daha iyi ergonomiye sahip, ancak iyi olan daha yüksek seviyeli bir şey istiyoruz. birleştirilebilirlik birlikte çalışan eşzamansız soyutlamalardan oluşan bir ekosistemi destekleyerek. Kulağa çok tanıdık geliyor: Uygulama ile aynı amaç takip edildi gelecekler(veya vaatler) şeklinde sözdizimsel şekeri destekleyen birçok dile zaman uyumsuz / bekliyor yukarıda.

İşlemciler tarafından desteklenen ilkel tamsayı türleri, gerçek hayatta kullanmaya alıştığımız sonsuz tamsayı kümesine sınırlı bir yaklaşımdır. Bu sınırlı gösterim her zaman "gerçek" sayılarla eşleşmez, örneğin 255_u8 + 1 == 0. Çoğu zaman programcı bu farkı unutur ve bu da kolayca hatalara yol açabilir.

Rust, hatalara karşı koruma sağlamayı amaçlayan bir programlama dilidir, en sinsi olan bellek hatalarını önlemeye odaklanır, ancak aynı zamanda programcının diğer sorunlardan kaçınmasına yardımcı olmaya çalışır: hataları ve göreceğimiz gibi, tamsayı taşmaları.

Demir hakkında biraz

Iron, Rust programlama dilinde yazılmış ve başka bir ünlü hiper kütüphanenin üzerine inşa edilmiş üst düzey bir web çerçevesidir. Demir, Rust'ın sunduğu avantajlardan tam olarak yararlanmak için tasarlanmıştır. Demir, çekirdeğindeki işlemleri engellemekten kaçınmaya çalışır.

Felsefe

Demir, mümkün olduğu kadar genişletilebilirlik ilkesi üzerine inşa edilmiştir. Kendi işlevselliğini genişletmek için konseptler sunar:

  • "Orta" özellikler, istek işlemede uçtan uca işlevselliği uygulamak için kullanılır;
  • değiştiriciler - istekleri ve yanıtları en ergonomik şekilde değiştirmek için kullanılır.

Makale boyunca değiştiricilerin ve ara özelliklerin temel kısmı ile tanışacaksınız.

Proje oluşturma

Öncelikle şu komutu kullanarak Cargo ile bir proje oluşturalım:

Derlemeden sonra ilgili yürütülebilir dosyayı alırız:

1 2 3 $ rustc merhaba.rs $ du -h merhaba 632K merhaba

Basit bir baskı için 632 kilobayt mı? Rust, C/C++'ın yerini alma potansiyeline sahip bir sistem dili olarak konumlanıyor, değil mi? Öyleyse neden en yakın rakibinizle benzer bir programa göz atmıyorsunuz?

Çevremizde, çöp toplayıcının avantajlarından birinin, yüksek performanslı, kilitsiz veri yapıları geliştirme kolaylığı olduğuna yaygın olarak inanılmaktadır. İçlerinde manuel bellek yönetimi kolay değildir ve GC bu sorunu kolayca çözer.

Bu gönderi, Rust kullanarak eşzamanlı veri yapıları için bir bellek yönetimi API'si oluşturmanın mümkün olduğunu gösterecek:

  • GC'nin yaptığı gibi kilitsiz bir veri yapısı uygulamayı mümkün kılın;
  • Bellek yönetimi şemasının kötüye kullanımına karşı statik koruma oluşturun;
  • GC ile karşılaştırılabilir genel giderlere sahip olacak (ve daha öngörülebilir).

Aşağıda göstereceğim testlerde Rust, Java'nın kilitsiz sıra uygulamalarından kolayca daha iyi performans gösteriyor ve Rust uygulamasının kendisini yazmak çok kolay.

Artık veri yapılarınızla kullanıma hazır olan yeni Crossbeam kitaplığında bir "çağa dayalı bellek geri kazanma" şeması uyguladım. Bu yazıda kilitsiz veri yapıları, epoch algoritması ve dahili Rust API hakkında konuşacağım.

Bellek erişim hataları ve bellek sızıntıları, en çok dikkat çeken iki hata kategorisidir, bu nedenle bunları önlemek veya en azından en aza indirmek için çok çaba harcanır. İsimleri bir benzerlik gösterse de, bir şekilde taban tabana zıttırlar ve sorunlardan birini çözmek bizi ikincisinden kurtarmaz. Yönetilen dillerin yaygın olarak benimsenmesi, bu fikre güven verir: belleği boşaltma işini üstlenerek bazı bellek erişim hatalarını önlerler.

Basit ifadeyle: bir bellek erişim ihlali, yanlış verilerle yapılan bir tür eylemdir ve bir bellek sızıntısı yokluk doğru verilerle belirli eylemler... Tablo şeklinde:

Programlama dillerini öğrenmekle ilgili birkaç düşüncem var.

Önce yanlış anlıyoruz. Aynı duyguyu eminim sizde yaşamışsınızdır. Yeni bir dil öğrenmeye çalışıyorsunuz ve dildeki her şeyin nasıl çalıştığını tam olarak anlamıyorsunuz. Neden bir sözdizimi bir yerde başka bir yerde kullanılıyor? Tüm bu tuhaflıklar can sıkıcı ve sonunda tanıdık dile dönüyoruz.

Dil algımızın bize acımasız bir şaka yaptığına inanıyorum. Yeni bir dili en son tartıştığınız zamanı düşünün. Birisi bundan bahsetti ve bir başkası hızı, sözdizimi veya mevcut web çerçevesi hakkında sorular sordu.

Arabalar hakkında konuşmaya çok benziyor. Yeni UAZ Rybak'ı duydunuz mu? Ne kadar hızlı? Gölün karşısına binebilir miyim?

Dillerden benzer şekilde bahsettiğimizde, onların değiştirilebilir olduğunu kastediyoruz. Makineler gibi. Lada Saransk'ı nasıl kullanacağımı bilirsem, UAZ Rybak'ı sorunsuz kullanabilirim. Tek fark hız ve gösterge tablosunda, değil mi?

Ama bir PHP arabasının nasıl görüneceğini hayal edin. Şimdi bir Lisp arabasının ne kadar farklı olacağını hayal edin. Birinden diğerine geçmek, ısıtmayı hangi düğmenin kontrol ettiğini öğrenmekten çok daha fazlasını gerektirecektir.

Not: Bu makale, okuyucunun Rust FFI (çeviri), endianess ve ioctl hakkında bilgi sahibi olduğunu varsaymaktadır.

C koduna bağlama oluştururken kaçınılmaz olarak birleşim içeren bir yapı ile karşılaşacağız. Rust, birleştirmeler için yerleşik desteğe sahip değil, bu yüzden kendimize strateji belirlememiz gerekecek. C'de bir birlik, aynı bellek alanında farklı veri türlerini depolayan bir türdür. Tam sayıların ve kayan noktalı sayıların ikili gösterimleri arasında dönüştürme, sözde polimorfizm uygulama ve bitlere doğrudan erişim gibi birleştirmeyi seçmenin birçok nedeni vardır. Sözde polimorfizme odaklanacağım.