Yol ve Modül Sistemi Değişiklikleri
Özet
usebildirimlerindeki yollar artık diğer yollarla aynı şekilde çalışır.::ile başlayan yollar artık bir harici crate ile devam etmelidir.pub(in path)görünürlük değiştiricilerindeki yollar artıkcrate,selfveyasuperile başlamalıdır.
Gerekçe
Modül sistemi, Rust’a yeni başlayanların en çok zorlandığı konulardan biridir. Elbette herkesin öğrenirken zaman alan farklı konuları vardır; ancak bunun bu kadar kafa karıştırıcı gelmesinin temel bir nedeni bulunuyor: Modül sistemini tanımlayan kurallar aslında basit ve tutarlı olsa da sonuçları çoğu zaman tutarsız, sezgiye aykırı ve gizemli görünebilir.
Bu yüzden Rust’ın 2018 sürümü, modül sistemine birkaç yeni özellik getirdi; ama sonuçta olan şey modül sisteminin sadeleşmesi oldu. Böylece neler olduğunu anlamak daha kolay hale geldi.
Kısa bir özet:
extern crate, durumların yüzde 99’unda artık gerekli değildir.crateanahtar kelimesi mevcut crate’i ifade eder.- Yollar, alt modüllerin içinde bile bir crate adıyla başlayabilir.
::ile başlayan yollar bir harici crate’i göstermelidir.ornek.rsveornek/alt dizini aynı anda var olabilir; alt modülleri bir alt dizine yerleştirirken artıkmod.rsgerekmez.usebildirimlerindeki yollar da diğer yollarla aynı şekilde çalışır.
Bu haliyle anlatılınca bunlar keyfi yeni kurallar gibi görünebilir; ama genel resme bakınca zihinsel model artık çok daha sade. Daha fazla ayrıntı için devam edelim.
Daha Fazla Ayrıntı
Şimdi bu yeni özelliklerin her birine sırayla bakalım.
Artık extern crate yok
Bu kısım oldukça açık: Bir crate’i projenize eklemek için artık extern crate
yazmanız gerekmiyor. Önceden şöyleydi:
// Rust 2015
extern crate futures;
mod alt_modul {
use futures::Future;
}
Sonrasında:
// Rust 2018
mod alt_modul {
use futures::Future;
}
Artık projenize yeni bir crate eklemek için onu Cargo.toml dosyanıza
eklemeniz yeterlidir; ikinci bir adım yoktur. Cargo kullanmıyorsanız, zaten
rustcye harici crate’lerin konumunu vermek için --extern bayraklarını
geçmeniz gerekiyordu; orada da yaptığınız şeyi yapmaya devam edersiniz.
Bir istisna
Bu kuralın bir istisnası vardır: “sysroot” crate’leri. Bunlar Rust’ın kendisiyle birlikte dağıtılan crate’lerdir.
Genelde bunlara yalnızca çok özel durumlarda ihtiyaç duyulur. 1.41 sürümünden
itibaren rustc, --extern=CRATE_NAME bayrağını kabul eder. Bu bayrak verilen
crate adını, extern crate benzeri bir şekilde otomatik olarak ekler. Derleme
araçları bunu sysroot crate’lerini crate’in prelude’una eklemek için
kullanabilir. Cargo’nun bunu genel biçimde ifade eden bir yolu yoktur; ancak
proc_macro crate’leri için bunu kullanır.
Sysroot crate’lerini açıkça içe aktarmanız gereken bazı durumlar şunlardır:
std: Genelde gerekli değildir; çünkü crate#![no_std]ile işaretlenmedikçestdotomatik olarak içe aktarılır.core: Genelde gerekli değildir; çünkü crate#![no_core]ile işaretlenmedikçecoreotomatik olarak içe aktarılır. Örneğin standart kütüphanenin kendi iç crate’lerinden bazıları buna ihtiyaç duyar.proc_macro: 1.42’den itibaren bir proc-macro crate’i söz konusuysa Cargo bunu otomatik olarak içe aktarır. Daha eski sürümleri desteklemek istiyorsanız veyarustcye uygun--externbayraklarını geçmeyen başka bir derleme aracı kullanıyorsanızextern crate proc_macro;gerekebilir.alloc:alloccrate’indeki öğelere geneldestdcrate’indeki yeniden dışa aktarmalar üzerinden erişilir. Eğer bellek ayırmayı destekleyen birno_stdcrate’i ile çalışıyorsanızalloccrate’ini açıkça içe aktarmanız gerekebilir.test: Bu yalnızca [nightly kanalda] kullanılabilir ve genelde kararsız kıyaslama desteği için kullanılır.
Makrolar
extern cratein bir başka kullanım alanı makro içe aktarmaktı; artık buna da
gerek yok. Makrolar da diğer öğeler gibi use ile içe aktarılabilir.
Örneğin aşağıdaki extern crate kullanımı:
#[macro_use]
extern crate bar;
fn main() {
baz!();
}
Şunun gibi bir kullanıma dönüştürülebilir:
use bar::baz;
fn main() {
baz!();
}
Crate adlarını yeniden adlandırma
Eğer crate’i şu şekilde as ile yeniden adlandırıyorsanız:
extern crate futures as f;
use f::Future;
yalnızca extern crate satırını silmek yetmez. Şunu yapmanız gerekir:
use futures as f;
use self::f::Future;
Bu değişiklik, f kullanan her modülde yapılmalıdır.
crate anahtar kelimesi mevcut crate’i ifade eder
use bildirimlerinde ve diğer kodlarda, mevcut crate’in köküne crate::
önekiyle başvurabilirsiniz. Örneğin crate::ornek::oge, aynı crate içindeki
nerede yazılırsa yazılsın hep ornek modülünün içindeki oge adına işaret eder.
:: öneki eskiden ya crate kökünü ya da harici bir crate’i gösteriyordu;
artık hiçbir belirsizlik olmadan harici bir crate’i gösterir. Örneğin
::harici::oge her zaman harici harici crate’inin içindeki oge adına gider.
Harici crate yolları
Önceden, bir modülde harici bir crate’i use ile içe aktarmadan kullanmak
istiyorsanız yolun başına :: koymanız gerekiyordu.
// Rust 2015
extern crate chrono;
fn islem() {
// bu kullanım crate kökünde çalışır
let x = chrono::Utc::now();
}
mod alt_modul {
fn fonksiyon() {
// ama alt modülde, `use` ile içe aktarılmadıysa başında `::` gerekir
let x = ::chrono::Utc::now();
}
}
Artık harici crate adları, alt modüller dahil tüm crate kapsamındadır.
// Rust 2018
fn islem() {
// bu kullanım crate kökünde çalışır
let x = chrono::Utc::now();
}
mod alt_modul {
fn fonksiyon() {
// crate'lere alt modüllerde bile doğrudan başvurulabilir
let x = chrono::Utc::now();
}
}
Eğer yerel bir modülünüzün ya da öğenizin adı harici bir crate ile aynıysa,
o adla başlayan yol yerel modülü ya da öğeyi gösterir. Harici crate’e açıkça
başvurmak için ::ad biçimini kullanın.
Artık mod.rs yok
Rust 2015’te bir alt modülünüz varsa:
// Bu `mod` bildirimi `ornek` modülünü
// `ornek.rs` veya `ornek/mod.rs` içinde arar.
mod ornek;
Bu modül ornek.rs ya da ornek/mod.rs içinde bulunabilir. Kendi alt
modülleri varsa dosyanın mutlaka ornek/mod.rs olması gerekir. Dolayısıyla
ornek modülünün içindeki oge alt modülü ornek/oge.rs yolunda olurdu.
Rust 2018’de, alt modülleri olan bir modülün adının mod.rs olmak zorunda
olması kısıtı kaldırıldı. ornek.rs dosyası olduğu gibi ornek.rs kalabilir;
alt modül de yine ornek/oge.rs olur. Böylece özel bir dosya adı kullanmak
zorunlu olmaktan çıkar. Düzenleyicide çok sayıda dosya açıkken de hepsinin adı
net biçimde görünür; ekranda üst üste mod.rs sekmeleri birikmez.
| Rust 2015 | Rust 2018 |
|---|---|
. ├── lib.rs └── ornek/ ├── mod.rs └── oge.rs |
. ├── lib.rs ├── ornek.rs └── ornek/ └── oge.rs |
use yolları
Rust 2018, Rust 2015’e göre yol kullanımını sadeleştirir ve birleştirir.
Rust 2015’te yollar use bildirimlerinde başka, diğer yerlerde başka türlü
çalışıyordu. Özellikle use bildirimlerindeki yollar her zaman crate kökünden
başlarken, diğer kodlarda yollar örtük olarak mevcut kapsamdan başlıyordu.
Bu farklar üst düzey modülde etkisini pek göstermediği için, her şey ancak alt
modülleri olan yeterince büyük bir projede kafa karıştırmaya başlıyordu.
Rust 2018’de ise use bildirimlerindeki yollarla diğer kodlardaki yollar hem
üst düzey modülde hem de alt modüllerde aynı şekilde çalışır. Mevcut kapsamdan
başlayan göreceli bir yol, harici crate adıyla başlayan bir yol ya da ::,
crate, super veya self ile başlayan bir yol kullanabilirsiniz.
Şöyle görünen kod:
// Rust 2015
extern crate futures;
use futures::Future;
mod ornek {
pub struct Oge;
}
use ornek::Oge;
fn benim_yoklamam() -> futures::Poll { ... }
enum BirEnum {
V1(usize),
V2(String),
}
fn islev() {
let bes = std::sync::Arc::new(5);
use BirEnum::*;
match ... {
V1(i) => { ... }
V2(s) => { ... }
}
}
Rust 2018’de de neredeyse aynı görünür; yalnızca extern crate satırını
silebilirsiniz:
// Rust 2018
use futures::Future;
mod ornek {
pub struct Oge;
}
use ornek::Oge;
fn benim_yoklamam() -> futures::Poll { ... }
enum BirEnum {
V1(usize),
V2(String),
}
fn islev() {
let bes = std::sync::Arc::new(5);
use BirEnum::*;
match ... {
V1(i) => { ... }
V2(s) => { ... }
}
}
Aynı kod, bir alt modül içinde de hiç değiştirilmeden çalışır:
// Rust 2018
mod alt_modul {
use futures::Future;
mod ornek {
pub struct Oge;
}
use ornek::Oge;
fn benim_yoklamam() -> futures::Poll { ... }
enum BirEnum {
V1(usize),
V2(String),
}
fn islev() {
let bes = std::sync::Arc::new(5);
use BirEnum::*;
match ... {
V1(i) => { ... }
V2(s) => { ... }
}
}
}
Bu yapı, proje içinde kodu bir yerden başka bir yere taşımayı kolaylaştırır ve çok modüllü projelere gereksiz ek karmaşıklık getirilmesini önler.