ProgramlamaRust Backend geliştirici

Rust'taki yöntemler ve ilişkili işlevler nasıl çalışır? Aralarındaki farklar nelerdir, nasıl duyurulurlar ve çağrılırlar, hangi durumlarda hangi seçenek kullanılmalıdır?

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

Cevap.

Soru tarihçesi

Rust, yöntemler kavramını nesne yönelimli dillerden ödünç alır, ancak bunları farklı bir şekilde gerçekleştirir: alışılmış olan this veya self yerine yöntemler açıkça bir self parametresi alır. İlişkili işlevler ise diğer dillerdeki statik yöntemlerin bir alternatifi olarak ortaya çıkmıştır — bunlar tip ile ilişkilidir, ancak belirli bir değere bağlı değildir.

Sorun

Sıklıkla yöntemler, ilişkili işlevler ve serbest işlevler karıştırılır. self içeren bir yöntemi ne zaman kullanmalı, self içermeyen bir ilişkili işlevi ne zaman kullanmalıyız? Görünürlük, otomatik dereferans, sahiplik aktarımı gibi sorunlar vardır.

Çözüm

Rust'taki yöntemler, impl bloğu içinde ilk parametre olarak self/ &self/ &mut self ile tanımlanır (genellikle struct veya enum için). Bir örnek üzerinde çağrılır: object.method(). İlişkili işlevler (örneğin, new, from) de impl içinde tanımlanır, ancak ilk parametre olarak self olmadan ve çift iki nokta ile çağrılır: Type::function().

Kod örneği:

struct Point { x: f64, y: f64, } impl Point { // İlişkili işlev (constructor) fn new(x: f64, y: f64) -> Self { Self { x, y } } // Yöntem: self'i gerektirir fn distance_from_origin(&self) -> f64 { (self.x.powi(2) + self.y.powi(2)).sqrt() } } let p = Point::new(3.0, 4.0); printf!("{}", p.distance_from_origin()); // 5.0

Ana özellikler:

  • Yöntemler, farklı sahiplik varyasyonlarında self parametresi alır
  • İlişkili işlevler self almaz, genellikle başlatma veya yardımcı görevler için kullanılır
  • Yalnızca yöntemler, örnek üzerinde nokta ile çağrılabilir; ilişkili işlevler yalnızca :: ile çağrılabilir

Kandırıcı sorular.

İlişkili işlevleri bir örnek üzerinden (nokta ile) çağırmak mümkün mü?

Bu olasıdır (örneğin, p.new(1.0, 2.0)), ancak son derece önerilmez: bu yanıltıcıdır çünkü ilişkili işlev mevcut nesneye erişime sahip değildir ve örnek göz ardı edilerek geçilir. Daha iyi bir kullanım Type::func() sentaksını kullanmaktır.

Kod örneği:

let p = Point::new(1.0, 2.0); let q = p.new(0.0, 0.0); // Çalışır, ama en iyi uygulama değil!

Yöntemler asenkron olabilir mi?

Evet. Yöntemler, serbest işlevler gibi async anahtar kelimesi ile tanımlanabilir:

impl Foo { async fn do_async(&self) { // ... } }

Bir impl bloğu içinde hem yöntemler hem de ilişkili işlevler tanımlamak mümkün mü?

Evet — her türlü kombinasyon mümkündür. Ayrıca, bir tip için birden fazla impl bloğu tanımlamak da mümkündür.

Tipik hatalar ve anti-desainler

  • Yöntemler ile ilişkili işlevleri karıştırmak
  • İlişkili işlevleri tiple ilişkisini belirtmeden bırakmak (impl içinde tanımlamamak)
  • İlişkili işlevleri bir örnek üzerinden çağırmak (nokta ile)

Hayattan bir örnek

Olumsuz vaka

Yeni başlayan birisi, new işlevini impl dışında tanımladı ve onu bir constructor olarak kullanmaya çalıştı; ardından yanlışlıkla bir örnek üzerinden çağırdı: p.new(1.0, 2.0).

Artılar:

Hızlı çalışır (derleyici buna izin verir).

Eksiler:

Kod okunaksız, bakım zor, self ile doğru yöntemler kullanmak zordur.

Olumlu vaka

Tüm yöntemler ve ilişkili işlevler, yalnızca impl içinde tanımlanmış olup, çağrı için doğru sözdizimleri kullanılmıştır (Type::new() constructorlar için, obj.method() eylemler için).

Artılar:

Yüksek okunabilirlik, en iyi uygulamalara uygunluk.

Eksiler:

Rust'ın deyimlerini bilme ve sözdizimine dikkat etme gerektirir.