Rust'ta tip dönüşümü için iki ayrı araç vardır. Birincisi std::convert modülündeki trait'lerdir: başarısız olamayan dönüşümler için From ve Into, başarısız olabilenler için TryFrom ve TryInto, ucuz referans dönüşümleri için AsRef ve AsMut. İkincisi as anahtar kelimesidir; sayısal tipler arasında hızlı ama kayıp olabilen dönüşüm yapar. Kısaca: u8::try_from(300) size bir hata döndürür, 300 as u8 ise sessizce 44 üretir.
Bu yazıda From uygulamanın neden Into uygulamaktan daha iyi olduğunu, TryFrom ile doğrulamalı dönüşüm yazmayı, as dönüşümünün tam kurallarını (kesme, işaret genişletme, ondalıktan tam sayıya doyma), AsRef ile hem String hem &str kabul eden fonksiyonları ve metinden değer üreten FromStr trait'ini çalışan örneklerle göreceksiniz. Trait ve generic temelleri trait ve generics yazılarında; serinin tamamı Rust öğrenme rehberi sayfasında.
From ve Into: başarısız olamayan dönüşümler

From<T> trait'i tek bir fonksiyon tanımlar: fn from(value: T) -> Self. Girdi değerini tüketerek (sahipliğini alarak) yeni tipte bir değer üretir. String::from("merhaba") ya da i64::from(5_i32) günlük kodda en sık gördüğünüz örneklerdir. Into<U> aynı ilişkinin ters yönüdür: fn into(self) -> U. Standart kütüphanede bir blanket implementation vardır: From<T> for U uygulandığında Into<U> for T kendiliğinden gelir. Bu yüzden belgeler açıktır: her zaman From uygulayın, Into uygulamayın. Ters yön geçerli değildir; elle yazılmış bir Into, From sağlamaz. Her iki trait de yansımalıdır (reflexive): her tip kendisine dönüşebilir.
From belgesi bir uygulamanın ne zaman uygun olduğunu dört özellikle tarif eder. Dönüşüm başarısız olmamalı (olabiliyorsa TryFrom kullanılır, panic üreten bir From yazılmaz), kayıpsız olmalı (bu yüzden i32: From<u16> vardır ama u16: From<u32> yoktur), değeri korumalı (bitleri aynı olsa da -1 ile 255 farklı kavramlar olduğu için u8: From<i8> yoktur, ama f32: From<i16> vardır) ve açık olmalıdır, yani iki tip arasındaki tek makul dönüşüm olmalıdır. Birden çok makul yol varsa adlandırılmış bir metot yazılır; u32::from_le_bytes ve u32::from_be_bytes bu yüzden ayrı metotlardır.
#[derive(Debug)]
struct Kurus(u64);
impl From<u32> for Kurus {
// Lira cinsinden tam sayı, kuruşa kayıpsız dönüşür
fn from(lira: u32) -> Self {
Kurus(lira as u64 * 100)
}
}
fn odeme_al(tutar: impl Into<Kurus>) -> Kurus {
tutar.into()
}
fn main() {
let a = Kurus::from(25);
let b: Kurus = 40.into(); // hedef tip notu gerekli
let c = odeme_al(3_u32);
println!("{:?} {:?} {:?}", a, b, c);
let s = String::from("çay");
let baytlar: Vec<u8> = s.into();
println!("{:?}", baytlar);
let genis = i64::from(-7_i32);
let ondalik = f64::from(2.5_f32);
println!("{} {}", genis, ondalik);
}
// çıktı: Kurus(2500) Kurus(4000) Kurus(300)
// çıktı: [195, 167, 97, 121]
// çıktı: -7 2.5Örnekte üç ayrıntıya dikkat edin. 40.into() tek başına yazılırsa derleyici hedef tipi bilemez; değişkene tip notu vermek gerekir. İkincisi, belgeler generic fonksiyon bound'larında From yerine Into kullanmayı önerir; odeme_al fonksiyonu impl Into<Kurus> alarak hem Kurus değerini (yansıma sayesinde) hem de u32 değerini kabul eder. Üçüncüsü, String tipinden Vec<u8> tipine dönüşüm UTF-8 baytlarını verir: "ç" iki bayttır (195, 167). Metin ve bayt ilişkisi String ve str yazısında.
TryFrom ve TryInto: doğrulamalı dönüşüm
Bazı dönüşümler çoğu zaman başarılı olur ama her zaman değil. i64 tipindeki bir değer i32 aralığına sığmayabilir; bunu From ile ifade etmek mümkün değildir, çünkü From kusursuz dönüşümler içindir. TryFrom<T> bu boşluğu doldurur: bir ilişkili hata tipi (type Error) ve Result<Self, Self::Error> döndüren try_from fonksiyonu tanımlar. From ile Into arasındaki ilişki burada da geçerlidir: TryFrom uygulamak TryInto sağlar. Edition Guide'a göre Rust 2021 edition ile TryFrom, TryInto ve FromIterator prelude'a eklendi; 2024 edition'da yazdığınız kodda bunları use ile içe aktarmanız gerekmez.
#[derive(Debug)]
struct Yuzde(u8);
impl TryFrom<i32> for Yuzde {
type Error = String;
fn try_from(deger: i32) -> Result<Self, Self::Error> {
if (0..=100).contains(°er) {
Ok(Yuzde(deger as u8))
} else {
Err(format!("{deger} yüzde olamaz"))
}
}
}
fn main() {
println!("{:?}", Yuzde::try_from(85));
println!("{:?}", Yuzde::try_from(140));
let y: Result<Yuzde, _> = (-3).try_into();
println!("{:?}", y);
// Standart tam sayı dönüşümleri
println!("{:?}", u8::try_from(300_i32));
println!("{:?}", i32::try_from(3_i64));
match u8::try_from(-1_i32) {
Ok(v) => println!("sığdı: {v}"),
Err(e) => println!("hata: {e}"),
}
}
// çıktı: Ok(Yuzde(85))
// çıktı: Err("140 yüzde olamaz")
// çıktı: Err("-3 yüzde olamaz")
// çıktı: Err(TryFromIntError(PosOverflow))
// çıktı: Ok(3)
// çıktı: hata: number too small to fit in target typeTam sayılar arası standart dönüşümler hata olarak TryFromIntError döndürür; Display çıktısı İngilizce bir mesajdır. TryFrom belgesi yansıma özelliğini de belirtir: T::try_from çağrısını aynı tipten bir değerle yaparsanız hata tipi Infallible olur, yani dönüşüm hiçbir zaman başarısız olamaz. Kendi tiplerinizde TryFrom, "doğrulanmış değer" tasarımının doğal bir parçasıdır: Yuzde tipinin bir örneği varsa değerin 0 ile 100 arasında olduğundan eminsinizdir.
as dönüşümü: kurallar ve sürprizler

as bir operatördür ve Reference'ta ayrıntılı bir tabloyla tanımlanır. Sayısal tipler arasında, alan taşımayan enum'dan tam sayıya, bool ve char tipinden tam sayıya, u8 tipinden char tipine ve çeşitli işaretçi tipleri arasında çalışır. Tabloda olmayan ve bir coercion kuralına da uymayan her dönüşüm derleme hatasıdır. as hiçbir zaman hata döndürmez; değer hedef tipe sığmıyorsa belirli kurallara göre başka bir değere dönüşür:
- Aynı boyuttaki tam sayılar (i32 ile u32 gibi) arasında dönüşüm bitleri değiştirmez; Rust negatif sayılar için ikiye tümleyen gösterimi kullandığından
-1_i8 as u8sonucu 255 olur. - Büyükten küçüğe tam sayı dönüşümü üst bitleri keser:
300_i32 as u8sonucu 44 olur (300 - 256). - Küçükten büyüğe dönüşümde kaynak işaretsizse sıfırla, işaretliyse işaret bitiyle genişletilir.
- Ondalıktan tam sayıya dönüşüm sıfıra doğru yuvarlar;
NaN0 olur, aralık dışındaki değerler (sonsuz dahil) hedef tipin en büyük veya en küçük değerine doyar (saturate). - Tam sayıdan ondalığa dönüşüm en yakın temsil edilebilir değeri verir; büyük tam sayılarda hassasiyet kaybolabilir.
- f64 tipinden f32 tipine dönüşüm en yakın
f32değerine yuvarlar, aralık dışı değerler sonsuz olur. Ters yön kayıpsızdır. - Enum dönüşümü discriminant değerini verir; yalnızca alan taşımayan enum'larda ve
Dropuygulamayan tiplerde izinlidir.
#[derive(Clone, Copy)]
enum Gun {
Pazartesi = 1,
Sali,
Carsamba,
}
fn main() {
println!("{} {} {}", 300_i32 as u8, -1_i8 as u8, 255_u8 as i8);
println!("{} {}", -17_i8 as i16, 200_u8 as i32);
println!("{} {} {}", 3.99_f64 as i32, -3.99_f64 as i32, f64::NAN as i32);
println!("{} {}", 1e10_f64 as i32, f64::NEG_INFINITY as u8);
println!("{} {}", 123_456_789_i32 as f32, u64::MAX as f64);
println!("{} {} {}", true as i32, 'A' as u32, 'ş' as u32);
println!("{} {}", 214_u8 as char, Gun::Carsamba as i32);
// Sessiz kesme yerine kontrollü yol
let buyuk: i64 = 5_000_000_000;
println!("{} {:?}", buyuk as i32, i32::try_from(buyuk).is_err());
let _ = Gun::Pazartesi as u8 + Gun::Sali as u8;
}
// çıktı: 44 255 -1
// çıktı: -17 200
// çıktı: 3 -3 0
// çıktı: 2147483647 0
// çıktı: 123456790 18446744073709552000
// çıktı: 1 65 351
// çıktı: Ö 3
// çıktı: 705032704 true123_456_789_i32 as f32 sonucunun 123456790 çıkması, f32 tipinin bu büyüklükte her tam sayıyı temsil edememesinden kaynaklanır. u8 tipinden char tipine dönüşüm yalnızca u8 için vardır, çünkü 0 ile 255 arasındaki her değer geçerli bir Unicode kod noktasıdır; u32 değerinden char almak için başarısız olabilen char::from_u32 veya char::try_from kullanılır. Genel kural şudur: değerin hedef tipe sığdığından emin değilseniz as yerine try_from kullanın; as ile kesilmiş bir değer çoğu zaman fark edilmeden sonraki hesaplara taşınır. Taşma davranışının genel resmi için veri tipleri yazısına bakın.
From ile dönüşüm olmayan durumlar: derleme hatası
Kayıplı bir dönüşümü From ile yapmaya çalışmak derleme anında yakalanır, çünkü standart kütüphane bu uygulamayı bilinçli olarak sağlamaz. Hata mesajı istenen trait bound'unu gösterir ve genellikle mevcut From uygulamalarını listeler:
fn main() {
let buyuk: i64 = 70_000;
let kucuk = i32::from(buyuk);
println!("{kucuk}");
}
// error[E0277]: the trait bound `i32: From<i64>` is not satisfiedBu hatanın iki doğru çözümü vardır: değerin sığacağını garanti edemiyorsanız i32::try_from(buyuk) ile Result alın ve hata durumunu işleyin; değerin taşmasını bilerek kabul ediyorsanız as kullanın ve bunu bir yorumla belgeleyin. E0277 hatasının genel okunuşu E0277 ve E0308 yazısında.
AsRef ve AsMut: ucuz referans dönüşümleri
AsRef<T>, bir referansı başka bir tipe ait referansa ucuza çeviren fn as_ref(&self) -> &T metodunu tanımlar. Değer tüketilmez ve yeni bellek ayrılmaz. En yaygın kullanımı generic fonksiyon parametreleridir: T: AsRef<str> yazdığınızda fonksiyon hem &str hem String kabul eder. Standart kütüphanedeki dosya fonksiyonlarının AsRef<Path> alması da bu yüzdendir; dosya okuma yazma yazısında görebilirsiniz. Pahalı bir dönüşüm gerekiyorsa belge AsRef yerine From uygulamayı ya da ayrı bir fonksiyon yazmayı önerir.
Belgenin iki inceliği bilinmeye değer. AsRef içteki tip bir referanssa kendiliğinden bir kat referans çözer; ancak bu tarihsel nedenlerle bütün akıllı işaretçiler için geçerli değildir. Yalnızca referans çözmek için as_ref yerine deref coercion kullanmak daha doğrudur: let y: &i32 = &x;. Ayrıca AsRef yansımalı değildir; her tip için AsRef<T> for T uygulaması kendiliğinden gelmez. Borrow trait'i aynı imzaya sahiptir ama ödünç alınan değerin Hash, Eq ve Ord davranışının sahip olunan değerle aynı olmasını şart koşar.
fn selamla<S: AsRef<str>>(ad: S) -> String {
let ad = ad.as_ref();
format!("Merhaba {}, adınız {} harf", ad, ad.chars().count())
}
fn sifirla<B: AsMut<[u8]>>(mut tampon: B) -> B {
for b in tampon.as_mut() {
*b = 0;
}
tampon
}
fn main() {
println!("{}", selamla("Çağrı"));
println!("{}", selamla(String::from("Ümit")));
let v = sifirla(vec![1_u8, 2, 3]);
let d = sifirla([9_u8; 4]);
println!("{:?} {:?}", v, d);
}
// çıktı: Merhaba Çağrı, adınız 5 harf
// çıktı: Merhaba Ümit, adınız 4 harf
// çıktı: [0, 0, 0] [0, 0, 0, 0]Metinden değere: FromStr ve parse

Metni sayıya veya kendi tipinize çevirmenin deyimsel yolu str::parse metodudur. parse arka planda FromStr trait'ini kullanır: type Err ilişkili tipi ve fn from_str(s: &str) -> Result<Self, Self::Err> fonksiyonu tanımlarsınız. Hedef tipi tip notuyla (let n: i32 = "5".parse()?) ya da turbofish ile ("5".parse::<i32>()) belirtirsiniz. Belgeye göre FromStr lifetime parametresi taşımadığı için yalnızca referans içermeyen tipler ayrıştırılabilir. Ters yön, yani değerden metne dönüşüm için ToString uygulanmaz; Display uygulanır ve to_string bedavaya gelir. Belgeler, Display çıktısı makine tarafından okunacaksa FromStr tarafının aynı biçimi kabul etmesini önerir:
use std::fmt;
use std::str::FromStr;
#[derive(Debug, PartialEq)]
struct Konum {
enlem: f64,
boylam: f64,
}
impl FromStr for Konum {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (a, b) = s.split_once(',').ok_or("virgül yok")?;
let enlem = a.trim().parse::<f64>().map_err(|e| e.to_string())?;
let boylam = b.trim().parse::<f64>().map_err(|e| e.to_string())?;
Ok(Konum { enlem, boylam })
}
}
impl fmt::Display for Konum {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}, {}", self.enlem, self.boylam)
}
}
fn main() {
let k: Konum = "39.92, 32.85".parse().unwrap();
println!("{:?}", k);
let metin = k.to_string();
println!("{} geri okunur mu: {}", metin, metin.parse::<Konum>() == Ok(k));
println!("{:?}", "39.92".parse::<Konum>());
println!("{:?}", "abc, 1".parse::<Konum>());
}
// çıktı: Konum { enlem: 39.92, boylam: 32.85 }
// çıktı: 39.92, 32.85 geri okunur mu: true
// çıktı: Err("virgül yok")
// çıktı: Err("invalid float literal")| Araç | Başarısız olabilir mi | Değeri tüketir mi | Tipik kullanım |
|---|---|---|---|
| From / Into | Hayır | Evet | Kayıpsız dönüşüm, ? ile hata dönüşümü |
| TryFrom / TryInto | Evet, Result döner | Evet | Aralık kontrolü, doğrulanmış tipler |
| AsRef / AsMut | Hayır | Hayır, referans verir | String ve &str kabul eden fonksiyonlar |
| FromStr / parse | Evet, Result döner | Hayır, &str okur | Metinden sayı veya tip üretmek |
| Display / to_string | Hayır | Hayır | Değerden metin üretmek |
| as | Hayır, sessizce keser veya doyar | Copy değerler | Bilinçli sayısal dönüşüm, enum discriminant |
Sık yapılan hatalar
Intouygulamak. Her zamanFromuygulayın;Intokendiliğinden gelir, tersi gelmez.- Panic üreten
Fromyazmak. Dönüşüm başarısız olabiliyorsaTryFromuygulayın. asile sessiz kesmeyi gözden kaçırmak.5_000_000_000_i64 as i32hata vermez, 705032704 üretir. Kullanıcıdan veya dış sistemden gelen değerlerdetry_fromkullanın.into()çağrısında hedef tipi belirtmemek. Derleyici hangiIntouygulamasını seçeceğini bilemez; değişkene tip notu verin.- Ondalıktan tam sayıya
asile yuvarlama beklemek.assıfıra doğru keser; 3.99 sonucu 3 olur. Yuvarlama için önceround()çağırın. u32 as charyazmak. Yalnızcau8tipindenchartipineasdönüşümü vardır; diğerleri içinchar::from_u32kullanın.
Sık Sorulan Sorular
From mu, Into mu kullanmalıyım?
Uygularken From, generic fonksiyon bound'u yazarken Into. Çağrı yerinde ikisi de çalışır; Tip::from(x) hedef tipi açıkça gösterdiği için çoğu zaman daha okunurdur.
as dönüşümü güvensiz mi?
Bellek açısından güvenlidir ve tanımsız davranış üretmez; kuralları Reference'ta tam olarak tanımlıdır. Sorun anlamsaldır: kesme ve doyma sessizce olur. Bu yüzden değerin sığdığından emin olmadığınız yerlerde try_from tercih edin.
String ile &str arasında nasıl dönüşüm yaparım?
&str tipinden String almak için String::from, to_string veya into; ters yön için &s ya da s.as_str() kullanılır. Ayrıntılar String ve str yazısında.
Kendi tipimi i32 değerine dönüştürmek için From<Tip> for i32 yazabilir miyim?
Evet. Orphan kuralı açısından tip sizin crate'inizde olduğu için impl From<Tip> for i32 geçerlidir. Belgeye göre bu, Rust 1.41 öncesinde mümkün değildi ve o dönemde Into elle uygulanırdı.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Rust öğrenme rehberi · Rust nedir · Rust veri tipleri · Rust String ve str · Rust özel hata tipi · Rust trait · E0277 ve E0308 hataları