Zero-cost abstractions — Rust'ın temel fikri, yani, abstractions (örneğin, generic türler, iteratorlar, trait'ler) el ile yazılan benzer kodlarla karşılaştırıldığında zaman veya bellek maliyetine neden olmamalıdır. Yani, yüksek seviye kod optimize edildikten sonra, düşük seviye kod kadar verimli bir şekilde derlenir.
Rust bunu monomorfizm mekanizması sayesinde gerçekleştirir: generic kod, dinamik çağrılar olmadan her bir spesifik tür için ayrı ayrı derlenir. Trait'ler/generics üzerinde yazılan iteratorlar ve closure'lar, optimize edildikten sonra derleyici tarafından doğrudan, katı bir şekilde türlendirilmiş koda açılır ve tüm gereksiz sarmalayıcılar kaldırılır.
Zero-cost iterator örneği:
let v = vec![1,2,3]; let sum: i32 = v.iter().map(|x| x * 2).sum();
Bu kod parçası optimize edildikten sonra derleyici tarafından neredeyse el ile yazılmış bir döngüye dönüşür:
let mut sum = 0; for x in &v { sum += x * 2; }
Rust'taki zero-cost abstraction, trait nesneleri kullanıldığında (örneğin, &dyn Trait) runtime overhead'inin olmayacağı anlamına mı geliyor?
Cevap: Hayır! Runtime-overhead, vtable aracılığıyla dinamik yöntem seçimi sırasında ortaya çıkar — generic fonksiyonlar yerine dyn Trait kullanıldığında. Zero-cost, yalnızca statik (monomorfize edilmiş) generic abstractions ile elde edilir.
Örnek:
trait Speaker { fn speak(&self); } fn say_twice<T: Speaker>(v: T) { v.speak(); v.speak(); } fn say_twice_dyn(v: &dyn Speaker) { v.speak(); v.speak(); } // İlk çağrı monomorfize edilir, ikincisi vtable aracılığıyladır
Hikaye
Hikaye
Hikaye
Bir dış kütüphanede, Box<dyn Trait> olarak döndürülen bir generic yapı oluşturduk. Generic uygulamasına rağmen, runtime'a çıkardığımız için zero-cost'u kaybettik.