Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Yol ve Modül Sistemi Değişiklikleri

Minimum Rust version: 1.31

Özet

  • use bildirimlerindeki 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ık crate, self veya super ile 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.
  • crate anahtar 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.rs ve ornek/ alt dizini aynı anda var olabilir; alt modülleri bir alt dizine yerleştirirken artık mod.rs gerekmez.
  • use bildirimlerindeki 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çe std otomatik olarak içe aktarılır.
  • core: Genelde gerekli değildir; çünkü crate #![no_core] ile işaretlenmedikçe core otomatik 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 veya rustcye uygun --extern bayraklarını geçmeyen başka bir derleme aracı kullanıyorsanız extern crate proc_macro; gerekebilir.
  • alloc: alloc crate’indeki öğelere genelde std crate’indeki yeniden dışa aktarmalar üzerinden erişilir. Eğer bellek ayırmayı destekleyen bir no_std crate’i ile çalışıyorsanız alloc crate’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ı

Minimum Rust version: 1.32

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.