- "Birleştirici" nin bir anlamı, birleştirici modeline atıfta bulunan, daha dolaylı anlam ifade eden, bir şeyleri birleştirme fikri etrafında merkezlenmiş kütüphaneleri düzenleme tarzıdır.
Genellikle bazı
T
türleri,T
türünün "temel" değerlerini oluşturmak için bir takım işlevler veT
türünün daha karmaşık değerlerini oluşturmak içinT
türü değerlerini çeşitli şekillerde birleştirebilen bazı “birleştiriciler” vardır. Diğer bir tanım ise "serbest değişkensiz işlev" anlamındadır. __ wiki.haskell.org - Birleştirici, program parçalarından yeni program parçaları oluşturan bir işlevdir. Birleştiricileri kullanan bir programcı bir anlamda her ayrıntıyı elle yazmaktan ziyade otomatik olarak olşturmayı tercih etmektedir. __ John Hughes — Monad'ların Oklarla genelleştirilmesi İşlevsel Programlama Kavramları'ndan.
Rust ekosistemindeki "birleştiriciler" in tam tanımı ise biraz belirsizdir.
-
or()
,and()
,or_else()
,and_then()
▸T
türündeki iki değişkeni birleştirerek ▸ aynıT
türünü döndürür. -
Option
türleri içinfilter()
▸ Koşullu bir işlevi bir kapama gibi kullanarak şarta göreT
türünü Filtreler ▸ aynıT
türünü döndürür. -
map()
,map_err()
▸T
türünü bir kapama işlevi uygulayarak dönüştürür. ▸ Bu işlem sırasındaT
içindeki değerin veri türü değişebilir. Örneğin:Some<&str>
Some<usize>
dönüştürülebileceği gibiErr<&str>
deErr<isize>
türüne dönüştürülebilir. -
map_or()
,map_or_else()
▸ Bir kapama işlevi uygulayarak dönüştürdüğüT
türü ve içindeki değerleri döndürür. ▸None
veErr
, için varsayılan bir değer ya da başka bir kapama işlevi uygulanır. -
Option
türleri içinok_or()
,ok_or_else()
▸Option
türünü birResult
türüne dönüştürür. -
as_ref()
,as_mut()
▸T
türünü bir referansa veya değişebilir bir referansa dönüştürür.
İki ifadeyi birleştirerek, Option
veya Result
türlerinden birini döndürür.
or()
metodu:Some
ya daOk
değerlerinden birisi varsa bu değer hemen döner.and()
metodu: Her iki ifadede deSome
veyaOk
değerlerinden biri bulunuyorsa, ikinci ifadedeki değer geriye döner. Bunlardan herhangi birindeNone
veyaErr
bulunuyorsa bu değer hızlıca döner.
fn main() {
let s1 = Some("some1");
let s2 = Some("some2");
let n: Option<&str> = None;
let o1: Result<&str, &str> = Ok("ok1");
let o2: Result<&str, &str> = Ok("ok2");
let e1: Result<&str, &str> = Err("error1");
let e2: Result<&str, &str> = Err("error2");
assert_eq!(s1.or(s2), s1); // Some1 veya Some2 = Some1
assert_eq!(s1.or(n), s1); // Some veya None = Some
assert_eq!(n.or(s1), s1); // None veya Some = Some
assert_eq!(n.or(n), n); // None1 veya None2 = None2
assert_eq!(o1.or(o2), o1); // Ok1 veya Ok2 = Ok1
assert_eq!(o1.or(e1), o1); // Ok veya Err = Ok
assert_eq!(e1.or(o1), o1); // Err veya Ok = Ok
assert_eq!(e1.or(e2), e2); // Err1 veya Err2 = Err2
assert_eq!(s1.and(s2), s2); // Some1 ve Some2 = Some2
assert_eq!(s1.and(n), n); // Some ve None = None
assert_eq!(n.and(s1), n); // None ve Some = None
assert_eq!(n.and(n), n); // None1 ve None2 = None1
assert_eq!(o1.and(o2), o2); // Ok1 ve Ok2 = Ok2
assert_eq!(o1.and(e1), e1); // Ok ve Err = Err
assert_eq!(e1.and(o1), e1); // Err ve Ok = Err
assert_eq!(e1.and(e2), e1); // Err1 ve Err2 = Err1
}
🔎 Rust'ın nightly sürümü
Option
türleri içinxor()
türünü desteklerken, yalnızca ifade bir tanesiSome
almışsayiSome
döndürür, ancak ikisini birden döndürmez.
or()
metoduna benzer. Farklı olarak, ikinci ifadenin aynı türden bir T
döndüren kapama işlevi olmasını şart koşar.
fn main() {
// `Option` için or_else()
let s1 = Some("some1");
let s2 = Some("some2");
// let fn_some = || -> Option<&str> { Some("some2") }; ifadesine benzer
let fn_some = || Some("some2");
let n: Option<&str> = None;
let fn_none = || None;
assert_eq!(s1.or_else(fn_some), s1); // Some1 or_else Some2 = Some1
assert_eq!(s1.or_else(fn_none), s1); // Some or_else None = Some
assert_eq!(n.or_else(fn_some), s2); // None or_else Some = Some
assert_eq!(n.or_else(fn_none), None); // None1 or_else None2 = None2
// `Result` için or_else()
let o1: Result<&str, &str> = Ok("ok1");
let o2: Result<&str, &str> = Ok("ok2");
// let fn_ok = |_| -> Result<&str, &str> { Ok("ok2") }; ifadesine benzer
let fn_ok = |_| Ok("ok2");
let e1: Result<&str, &str> = Err("error1");
let e2: Result<&str, &str> = Err("error2");
let fn_err = |_| Err("error2");
assert_eq!(o1.or_else(fn_ok), o1); // Ok1 or_else Ok2 = Ok1
assert_eq!(o1.or_else(fn_err), o1); // Ok or_else Err = Ok
assert_eq!(e1.or_else(fn_ok), o2); // Err or_else Ok = Ok
assert_eq!(e1.or_else(fn_err), e2); // Err1 or_else Err2 = Err2
}
and()
metoduna benzer. Tek fark, ikinci ifadenin aynı türden T
döndüren bir kapama işlevi olmasını şart koşar.
fn main() {
// `Option` için and_then()
let s1 = Some("some1");
let s2 = Some("some2");
// let fn_some = |_| -> Option<&str> { Some("some2") }; ifadesine benzer
let fn_some = |_| Some("some2");
let n: Option<&str> = None;
let fn_none = |_| None;
assert_eq!(s1.and_then(fn_some), s2); // Some1 and_then Some2 = Some2
assert_eq!(s1.and_then(fn_none), n); // Some and_then None = None
assert_eq!(n.and_then(fn_some), n); // None and_then Some = None
assert_eq!(n.and_then(fn_none), n); // None1 and_then None2 = None1
// // `Result` için and_then()
let o1: Result<&str, &str> = Ok("ok1");
let o2: Result<&str, &str> = Ok("ok2");
// let fn_ok = |_| -> Result<&str, &str> { Ok("ok2") }; ifadesine benzer
let fn_ok = |_| Ok("ok2");
let e1: Result<&str, &str> = Err("error1");
let e2: Result<&str, &str> = Err("error2");
let fn_err = |_| Err("error2");
assert_eq!(o1.and_then(fn_ok), o2); // Ok1 and_then Ok2 = Ok2
assert_eq!(o1.and_then(fn_err), e2); // Ok and_then Err = Err
assert_eq!(e1.and_then(fn_ok), e1); // Err and_then Ok = Err
assert_eq!(e1.and_then(fn_err), e1); // Err1 and_then Err2 = Err1
}
💡
filter()
metodları programlama dillerinde genellikle, dizi veya yineleyicilerin bir kapama veya işlev yardımıyla filtrelenerek yeni bir dizi veya yineleyici oluşturulması işlerinde kullanılır. Ek olarak Rust bir yineleyicinin, başka bir yineleyiciye dönüştürülebilmesi için, bir kapama işevi aracılığıyla dönüştürülmek istenilen yineleyicinin her bir elemanına uygulanabilecek yineleyici adaptörü olarak kullanılabilen birfilter()
metodu sağlar. Yalnız buradaOption()
türleriyle kullanılabilen birfilter ()
işlevselliğinden bahsettiğimizi anımsatmam yerinde olur.
Eğer bir kapama işlevine tek bir Some
değeri iletilirse ve bu işlevden true
döndürülürse aynı türden bir Some
döndürülmüş olur. Fakat kapama işlevine None
değeri iletiliyor ve işlevden false
döndürülüyorsa bu durumda bir None
geriye döndürülür. Kapama işlevleri Some
içinde bulunan değeri bağımsız değişken olarak kullanırlar. Rust'ta halen filter()
desteği sadece Option
türleri için kullanılabilmektedir.
fn main() {
let s1 = Some(3);
let s2 = Some(6);
let n = None;
let fn_cift_mi = |x: &i8| x % 2 == 0;
assert_eq!(s1.filter(fn_cift_mi), n); // Some(3) -> 3 çift değil -> None
assert_eq!(s2.filter(fn_cift_mi), s2); // Some(6) -> 6 çift -> Some(6)
assert_eq!(n.filter(fn_cift_mi), n); // None -> değer taşımıyor -> None
}
💡 Bunlar programlama dillerinde genellikle, dizi veya yineleyicilerle kullanılan ve bir kapama işlevinin koleksiyonun her bir elemanına ayrı ayrı uygulanmasını sağlayan metodlardır. Ek olarak Rust bir yineleyicinin her bir öğesini başka bir yineleyiciye dönüştürebilmek maksadıyla kapama olarak uygulanabilen bir yineleyici adaptörü olan
map()
metodunu sunar. Elbette ki burada daOption
veResult
türleri ile kullanılabilen birmap()
işlevselliğinden bahsettiğimizi hatırlatmak zorundayım.
map()
:T
türlerini bir kapama uygulayarak dönüştürür.Some
veyaOk
bloklarının veri türü, kapamanın dönüş türüne göre değiştirilebilir. Başka bir ifadeyleOption<T>
türüOption<U>
türüne ya daResult<T, E>
türüResult<U, E>
türüne dönüştürülebilir.
⭐ map()
metodlarıyla sadece Some
ve OK
değerlerinin değişebileceğini Err
içindeki değerlerin etkinmeyeceğini hatırlamanız gerekir. Bir Option
varyantı olan None
türünün ise zaten hiçbir değeri içermeyeceğini zaten biliyorsunuz.
fn main() {
let s1 = Some("abcde");
let s2 = Some(5);
let n1: Option<&str> = None;
let n2: Option<usize> = None;
let o1: Result<&str, &str> = Ok("abcde");
let o2: Result<usize, &str> = Ok(5);
let e1: Result<&str, &str> = Err("abcde");
let e2: Result<usize, &str> = Err("abcde");
let fn_karakter_adedi = |s: &str| s.chars().count();
assert_eq!(s1.map(fn_karakter_adedi), s2); // Some1 map = Some2
assert_eq!(n1.map(fn_karakter_adedi), n2); // None1 map = None2
assert_eq!(o1.map(fn_karakter_adedi), o2); // Ok1 map = Ok2
assert_eq!(e1.map(fn_karakter_adedi), e2); // Err1 map = Err2
}
map_err()
:Ressult
türleri için kullanılır. Kapama işlevinin dönüş türüne göreErr
bloklarının veri türü değiştirilebilir. Başka bir ifadeyleResult<T, E>
türüResult<T, F>
türüne dönüştürülebilir.
⭐ map_err()
metodu ile yalnızca Err
değerlerinin değiştirilebileceğini Ok
içeriğinin bundan etkilenmeyeceğini unutmayınız.
fn main() {
let o1: Result<&str, &str> = Ok("abcde");
let o2: Result<&str, isize> = Ok("abcde");
let e1: Result<&str, &str> = Err("404");
let e2: Result<&str, isize> = Err(404);
//str den isize türüne dönüşür
let fn_karakter_adedi = |s: &str| -> isize { s.parse().unwrap() };
assert_eq!(o1.map_err(fn_karakter_adedi), o2); // Ok1 map = Ok2
assert_eq!(e1.map_err(fn_karakter_adedi), e2); // Err1 map = Err2
}
Daha önce işlediğimiz unwrap_or()
ve unwrap_or_else()
metodlarının işlevselliğini hatırladığınızı sanıyorum. Bu metodlar onların birer benzeridir. Ancak map_or()
ve map_or_else()
metodları, Some
ve Ok
değerlerine bir kapatma uygulayarak işlenilen değeri T
türü içinde döndürür.
map_or():
YalnızcaOption
türlerini desteklerResult
türünü desteklemez. Kapama işleviniSome
içindeki değerlere uygulayarak kapamadan iletilen çıktıyı döndürür.None
türleri içinse belirlenmiş varsayılan bir değer döndürülür.
fn main() {
const VARSAYILAN_D: i8 = 1;
let s = Some(10);
let n: Option<i8> = None;
let kapama = |v: i8| v + 2;
assert_eq!(s.map_or(VARSAYILAN_D, kapama), 12);
assert_eq!(n.map_or(VARSAYILAN_D, kapama), VARSAYILAN_D);
}
map_or_else():
HemOption
hemResult
türlerini destekler.Map_or()
metoduna benzemekle beraber, ilk parametre için varsayılan değer yerine başka bir kapama işlevin sunulması gerekir.
⭐ N türü hiçbir değer içermediğinden Option
türleri söz konusu olduğunda kapama işlevine girdi olarak bir şey iletmeye gerek yoktur. Bununla birlikte Err
türlerinde bir parça bilgi içerdiğinden, bu metodun Result
türleriyle kullanımında kapama işlevi tarafından girdi olarak okunabilmesi gereklidir.
// nightly sürümünde bulunan kararsız kütüphane
// özelliğinin etkinleştirilmesi
#![feature(result_map_or_else)]
fn main() {
let s = Some(10);
let n: Option<i8> = None;
// `None` bir değer içermediğinden kapamaya giriş olarak iletmeye gerek yok
let fn_kapama = |v: i8| v + 2;
let fn_varsay = || 1;
assert_eq!(s.map_or_else(fn_varsay, fn_kapama), 12);
assert_eq!(n.map_or_else(fn_varsay, fn_kapama), 1);
let o = Ok(10);
let e = Err(5);
// `Err` ise bir parça veri içerdiğinden varsayılan kapama
// kapama işlevi tarafından giriş olarak okunabilmelidir
let fn_result_icin_varsay = |v: i8| v + 1;
assert_eq!(o.map_or_else(fn_result_icin_varsay, fn_kapama), 12);
assert_eq!(e.map_or_else(fn_result_icin_varsay, fn_kapama), 6);
}
Daha önce de belirtildiği gibi ok_or()
ve ok_or_else()
metodları Option
türünü Result
türüne dönüştürür. Başka bir ifadeyle Some
türü Ok
türüne, None
türü de Err
türüne dönüştürülür.
ok_or():
Varsayılan birErr
mesajı bağımsız değişken olarak iletilmelidir.
fn main() {
const ERR_VARSAY: &str = "Hata mesajı";
let s = Some("abcde");
let n: Option<&str> = None;
let o: Result<&str, &str> = Ok("abcde");
let e: Result<&str, &str> = Err(ERR_VARSAY);
assert_eq!(s.ok_or(ERR_VARSAY), o); // Some(T) -> Ok(T)
assert_eq!(n.ok_or(ERR_VARSAY), e); // None -> Err(varsayılan)
}
ok_or_else()
:ok_or()
metoduna benzer. Argüman olarak bir kapama geçirilmelidir.
fn main() {
let s = Some("abcde");
let n: Option<&str> = None;
let fn_hata_iletisi = || "Hata mesajı";
let o: Result<&str, &str> = Ok("abcde");
let e: Result<&str, &str> = Err("Hata mesajı");
assert_eq!(s.ok_or_else(fn_hata_iletisi), o); // Some(T) -> Ok(T)
assert_eq!(n.ok_or_else(fn_hata_iletisi), e); // None -> Err(varsayılan)
}
🔎 Daha önce belirtildiği gibi bu metodlar bir T
türünü, referans ya da değişebilir referans olarak ödünç almak amacıyla kullanılır.
as_ref()
:Option<T>
türünüOption<&T>
türüne, veResult<T, E>
türünüResult<&T, &E>
türüne dönüştürür.as_mut()
:Option<T>
türünüOption<&mut T>
türüne, veResult<T, E>
türünüResult<&mut T, &mut E>
türüne dönüştürür.