- "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ı
Ttürleri,Ttürünün "temel" değerlerini oluşturmak için bir takım işlevler veTtürünün daha karmaşık değerlerini oluşturmak içinTtü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()▸Ttüründeki iki değişkeni birleştirerek ▸ aynıTtürünü döndürür. -
Optiontürleri içinfilter()▸ Koşullu bir işlevi bir kapama gibi kullanarak şarta göreTtürünü Filtreler ▸ aynıTtürünü döndürür. -
map(),map_err()▸Ttürünü bir kapama işlevi uygulayarak dönüştürür. ▸ Bu işlem sırasındaTiç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üğüTtürü ve içindeki değerleri döndürür. ▸NoneveErr, için varsayılan bir değer ya da başka bir kapama işlevi uygulanır. -
Optiontürleri içinok_or(),ok_or_else()▸Optiontürünü birResulttürüne dönüştürür. -
as_ref(),as_mut()▸Ttü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:Someya daOkdeğerlerinden birisi varsa bu değer hemen döner.and()metodu: Her iki ifadede deSomeveyaOkdeğerlerinden biri bulunuyorsa, ikinci ifadedeki değer geriye döner. Bunlardan herhangi birindeNoneveyaErrbulunuyorsa 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ü
Optiontürleri içinxor()türünü desteklerken, yalnızca ifade bir tanesiSomealmışsayiSomedö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 daOptionveResulttürleri ile kullanılabilen birmap()işlevselliğinden bahsettiğimizi hatırlatmak zorundayım.
map():Ttürlerini bir kapama uygulayarak dönüştürür.SomeveyaOkblokları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():Ressulttürleri için kullanılır. Kapama işlevinin dönüş türüne göreErrblokları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ızcaOptiontürlerini desteklerResulttürünü desteklemez. Kapama işleviniSomeiçindeki değerlere uygulayarak kapamadan iletilen çıktıyı döndürür.Nonetü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():HemOptionhemResulttü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 birErrmesajı 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.