RustProgramlamaRust Geliştirici

**Rust**'ın sabit genel parametreler olarak kayan nokta türlerini veya dize literallerini kabul etmesini engelleyen tür sistemi kısıtlamalarını değerlendirin ve derleyicinin bu kısıtlamaları monomorfizasyon sırasında nasıl uyguladığını açıklayın.

Hintsage yapay zeka asistanı ile mülakatları geçin

Sorunun cevabı.

Tarih: Sabit genel türler, Rust 1.51'de ilkel tam sayı türlerinin sabit değerleri ile parametreleştirilmesine izin vermek için stabilize edilmiştir ve bu, [T; N] gibi genel sabit boyutlu dizilere olanak tanır. Tasarım aşamasında, dil ekibi sabit genel parametreleri yapısal eşitlik ve belirleyici derleme zamanı değerlendirmesi sergileyen türlerle sınırlamayı açıkça belirledi. Bu kısıtlama, toplam sıralamayı ihlal eden veya zaman çalışması bellek adreslerine bağımlı olan f32, f64 ve &str literallerini hariç tutmuştur.

Problem: Kayan nokta türlerinin temel sorunu, NaN (Sayısal Olmayan) varlığıdır; bu, yansımalı eşitliği ihlal eder (NaN != NaN), bu da derleyicinin monomorfizasyon sırasında tür kimliğini güvenilir bir şekilde belirlemesini engeller. Dize literalleri (&str) ile ilgili sorun, kalın işaretçi temsilidir (adres + uzunluk) ve veri segmentindeki belirli bellek adreslerine olan bağımlılıklarıdır, bu da derleme birimleri veya crate'ler arasında belirleyici değildir. Tür sistemi, MyStruct<1> ve MyStruct<1>'in her zaman aynı türü ifade etmesini gerektirir, bu da sabit parametrenin eşitliğinin derleme zamanında bit ve yapısal karşılaştırma ile kararlaştırılabilir olması gerektiği anlamına gelir.

Çözüm: Rust derleyicisi bu kısıtlamaları HIR (Yüksek Düzeyli Ara Temsil) düşürülmesi ve tür kontrolü sırasında StructuralPartialEq (istikrarsız) gibi iç taslaklar aracılığıyla uygular. Bir sabit genel parametre ile karşılaştığında, derleyici türün bir tam sayı, bool veya char veya yapısal eşitliği desteklediği açıkça işaretlenmiş bir kullanıcı tanımlı tür olduğundan emin olur. Kayan nokta türlerini yansımalı eşitliğin olmaması nedeniyle reddeder ve &str gibi referansları reddeder çünkü bunlar 'static bağlamında uzlaşamayacak yaşam süreleri ve dolaylılık getirir. Monomorfizasyon sırasında, derleyici sabit ifadeleri değerlendirir ve aynılaştırılabilir yapı eşitliğini kullanarak benzer örnekleri birleştirir, tür güvenliğini sağlar.

// Geçerli: usize yapısal eşitliğe sahiptir struct Matrix<const N: usize> { data: [[f64; N]; N], } // Geçersiz: f64 toplam sıralamadan yoksundur (NaN sorunları) // struct Physics<const G: f64>; // Hata: kayan nokta türleri sabit genel türlerde kullanılamaz // Geçersiz: &str dolaylılık ve yaşam süreleri karmaşıklığına sahiptir // struct Label<const S: &str>; // Hata: `&str` sabit genel parametre türü olarak yasaktır

Hayattan bir durum

Yüksek frekanslı bir ticaret motoru tasarlıyorsunuz; burada finansal araçların sözleşme özelikleri için derleme zamanı sabit parametreler taşıması gerekir, örneğin tok boyutları (örn. 0.25 USD) veya çarpan katsayıları. İlk tasarım, bu hassas ondalık değerleri doğrudan tür sistemi içine kodlayabilmek amacıyla f64 sabit genel türlerini kullanmayı denedi ve bu sayede bu sabitlerin zaman çalışma depolamasını ortadan kaldırmayı ve fiyat hesaplamalarının derleme zamanında optimize edilmesini hedefledi.

Dikkate alınan yaklaşımlardan biri, f64 bitlerini u64'e çevirip bunu sabit parametre olarak kullanmaktı, ardından uygulama içinde geri çevirerek. Ancak, bu, bitwise olarak aynı olan float'ların, işaretli sıfır (+0.0 ile -0.0) ve NaN yükleri nedeniyle farklı anlamlı değerler temsil edebilmesi nedeniyle tehlikeli olduğu kanıtlandı ve bu durum derleyicinin farklı finansal araçları aynı türde olarak değerlendirmesine veya ayrı kalması gereken hesaplamaları birleştirmesine neden olabileceği için yanlış fiyatlandırma mantığına yol açabilirdi.

Bir başka çözüm, bir özellik içinde ilişkili sabitler kullanmaktı (trait Instrument { const TICK_SIZE: f64; }). Bu, kayan nokta değerlerine izin verse de, tik boyutunu bir tür düzeyindeki ayırt edici olarak kullanabilme yeteneğini feda eder; Vec<Instrument<TICK_SIZE>> içinde farklı tik boyutlarına sahip farklı araçların bulunabilmesi mümkün değildir, bunun yerine dyn Trait nesne aşınmasının getirdiği dolaylılık kabul edilemez, özellikle hızlı yolda.

Seçilen çözüm, kayan nokta değerlerini sabit nokta tam sayıları olarak kodlamak oldu (örn. 0.25 USD'yi usize 25 olarak, 100'lük bir ölçek faktörü ile temsil etmek). Bu yaklaşım, sabit genel kısıtlamalarını yerine getirirken sıfır maliyetli soyutlama ve derleme zamanı değerlendirilmesi sağlar. Sonuç, Bond<25> ve Bond<50>'nin hiçbir zaman çalışma aşaması olmadan ayrı türler olduğu tür güvenli bir sözleşme sistemiydi, ancak bu, aritmetik hataları önlemek için ölçeklendirme konvansiyonunun dikkatlice belgelenmesini gerektirdi.

Adayların sıklıkla atladığı noktalar

Rust, neden char ve bool'ü sabit genel parametreler olarak kabul ederken &str'yi hariç tutuyor, her ikisi de teknik olarak ilkel türlerdir?

Char ve bool sabit boyutlu ve önemsiz yapısal eşitliğe sahip değer türleridir; bir char 32 bit Unicode scalar değeridir ve bool katı bir şekilde 0 veya 1'dir, bu da bitwise karşılaştırmayı olanaklı kılar. &str, dolaylı bir işaretçi (veya DST üzerindeki bir referans) olup, bir veri işaretçi ve bir uzunluk içerir, dolaylılık ve yaşam süreleri parametreleri getirir. Derleyici, iki dize literalinin farklı crate'ler arasında aynı bellek adresinde bulunmasını garanti edemez ya da yaşam sürelerinin 'static gereksinimlerini karşılayıp karşılamadığını kontrol edemez. Sonuç olarak, &str sabit genel parametreler için gerekli yapısal özellikleri taşımazken, char ve bool kendi kendine yeterli değerlerdir.

Kayan nokta türleri için sabit genel uygulaması, NaN (Sayısal Olmayan) değerleri açısından tür güvenliğini nasıl potansiyel olarak ihlal edebilir?

Eğer f32 izin verilseydi, ifadeler MyStructf32::NAN ve MyStruct<{ 0.0 / 0.0 }> her ikisi de NaN değerlerini üretecekti, ancak derleyici bunların aynı türü temsil ettiğini garanti edemezdi çünkü NaN != NaN. Bu, mantıken aynı tür olmalı olan iki ayrı monomorfizasyonun yaratılmasına ya da bunun tersine, derleyicinin farklı NaN yüklerine sahip türleri yanlış bir şekilde birleştirmesine neden olabilirdi. Bu tür kimliğinin ihlali, singleton kalıplarının başarısız olmasına veya tür tabanlı optimizasyonların yanlış kod üretmesine yol açabilecek bir güvensizlik oluşturabilir, çünkü derleyici tür parametrelerinin benzersiz bir türü tanımladığını varsayar.

Sabit genel türler ile ilişkili sabitler arasındaki temel ayrım nedir ve neden ilki yapısal eşitlik gerektirirken, ikincisi gerektirmez?

Sabit genel parametreler, tür kimliğinin bir parçasıdır; Container<10> ve Container<20> ayrı türler olup, ayrı monomorfizasyonlara sahiptir. Bu, değerlerin derleme zamanı karşılaştırılabilir olmasını gerektirir, böylece küresel benzersizlik sağlanır ve kimlikleri birleştirilebilir. İlişkili sabitler, bir tür uygulaması ile ilgili değerlerdir, ancak türü değiştirmez; TypeA ve TypeB ilişkili sabit değerlerine bağlı olarak ayrı türlerdir. Bu nedenle, ilişkili sabitler kayan nokta veya karmaşık türler olabilir çünkü yalnızca uygulama içinde değer sağlar, tür kontrolü veya monomorfizasyonu etkilemeden, tür sistemi düzeyinde yapısal eşitlik gereksinimini atlayarak.