Rust'ta varsayılan bağımsız değişkenli bir işlev oluşturmak mümkün müdür?
fn add(a: int = 1, b: int = 2) { a + b }
Rust'ta varsayılan bağımsız değişkenli bir işlev oluşturmak mümkün müdür?
fn add(a: int = 1, b: int = 2) { a + b }
Option
ve açıkça geçirmelisiniz None
.
Yanıtlar:
Hayır, şu anda değil. Eninde sonunda uygulanacağını düşünüyorum, ancak şu anda bu alanda aktif bir çalışma yok.
Burada kullanılan tipik teknik, farklı adlara ve imzalara sahip işlevleri veya yöntemleri kullanmaktır.
Varsayılan argümanlar desteklenmediğinden benzer bir davranış elde edebilirsiniz. Option<T>
fn add(a: Option<i32>, b: Option<i32>) -> i32 {
a.unwrap_or(1) + b.unwrap_or(2)
}
Bu, varsayılan değer ve işlevin yalnızca bir kez kodlanması (her çağrıda yerine) hedefini gerçekleştirir, ancak elbette yazılması çok daha fazla şey vardır. add(None, None)
Bakış açınıza bağlı olarak beğenebileceğiniz veya beğenmeyeceğiniz işlev çağrısı gibi görünecektir .
Kodlayıcı potansiyel olarak bir seçim yapmayı unuttuğundan bağımsız değişken listesine hiçbir şey yazmadığınızı görürseniz, buradaki en büyük avantaj açıklıktır; arayan açıkça sizin varsayılan değerinizle gitmek istediğini ve hiçbir şey koymazsa bir derleme hatası alacağını söylüyor. Yazmak olarak düşünün add(DefaultValue, DefaultValue)
.
Ayrıca bir makro da kullanabilirsiniz:
fn add(a: i32, b: i32) -> i32 {
a + b
}
macro_rules! add {
($a: expr) => {
add($a, 2)
};
() => {
add(1, 2)
};
}
assert_eq!(add!(), 3);
assert_eq!(add!(4), 6);
İki çözüm arasındaki en büyük fark, "Seçenek" argümanlarıyla yazmanın tamamen geçerli olmasıdır add(None, Some(4))
, ancak makro örüntü eşleşmesiyle yapamazsınız (bu, Python'un varsayılan argüman kurallarına benzer).
Ayrıca bir "bağımsız değişkenler" yapısı ve From
/ Into
nitelikleri de kullanabilirsiniz :
pub struct FooArgs {
a: f64,
b: i32,
}
impl Default for FooArgs {
fn default() -> Self {
FooArgs { a: 1.0, b: 1 }
}
}
impl From<()> for FooArgs {
fn from(_: ()) -> Self {
Self::default()
}
}
impl From<f64> for FooArgs {
fn from(a: f64) -> Self {
Self {
a: a,
..Self::default()
}
}
}
impl From<i32> for FooArgs {
fn from(b: i32) -> Self {
Self {
b: b,
..Self::default()
}
}
}
impl From<(f64, i32)> for FooArgs {
fn from((a, b): (f64, i32)) -> Self {
Self { a: a, b: b }
}
}
pub fn foo<A>(arg_like: A) -> f64
where
A: Into<FooArgs>,
{
let args = arg_like.into();
args.a * (args.b as f64)
}
fn main() {
println!("{}", foo(()));
println!("{}", foo(5.0));
println!("{}", foo(-3));
println!("{}", foo((2.0, 6)));
}
Bu seçim açıkça çok daha fazla koddur, ancak makro tasarımından farklı olarak tür sistemini kullanır, bu da derleyici hatalarının kitaplığınız / API kullanıcınız için daha yararlı olacağı anlamına gelir. Bu aynı zamanda, From
eğer kendilerine yardımcı olacaksa , kullanıcıların kendi uygulamalarını yapmalarına da olanak tanır .
Hayır, Rust varsayılan işlev bağımsız değişkenlerini desteklemez. Farklı isimlerle farklı yöntemler tanımlamalısınız. Rust, türleri türetmek için işlev adlarını kullandığından (işlev aşırı yükleme bunun tersini gerektirir), çünkü işlev aşırı yüklemesi yoktur.
Yapı başlatma durumunda, yapı güncelleme sözdizimini şu şekilde kullanabilirsiniz:
use std::default::Default;
#[derive(Debug)]
pub struct Sample {
a: u32,
b: u32,
c: u32,
}
impl Default for Sample {
fn default() -> Self {
Sample { a: 2, b: 4, c: 6}
}
}
fn main() {
let s = Sample { c: 23, .. Sample::default() };
println!("{:?}", s);
}
[istek üzerine, bu yanıtı yinelenen bir sorudan çapraz olarak gönderdim]
Rust varsayılan işlev argümanlarını desteklemiyor ve gelecekte uygulanacağına da inanmıyorum. Bu yüzden makro formda uygulamak için bir proc_macro duang yazdım .
Örneğin:
duang! ( fn add(a: i32 = 1, b: i32 = 2) -> i32 { a + b } );
fn main() {
assert_eq!(add!(b=3, a=4), 7);
assert_eq!(add!(6), 8);
assert_eq!(add(4,5), 9);
}
Rust 1.12 veya sonraki bir sürümünü kullanıyorsanız, en azından işlev argümanlarının Option
ve ile kullanımını kolaylaştırabilirsiniz into()
:
fn add<T: Into<Option<u32>>>(a: u32, b: T) -> u32 {
if let Some(b) = b.into() {
a + b
} else {
a
}
}
fn main() {
assert_eq!(add(3, 4), 7);
assert_eq!(add(8, None), 8);
}
Diğer bir yol, her seçenek için doğru türü alacak şekilde parametrelendirilebilen, isteğe bağlı parametrelerle değişken olarak bir enum bildirmek olabilir. Fonksiyon, enum varyantlarının değişken uzunluklu bir dilimini almak için uygulanabilir. Herhangi bir sırada ve uzunlukta olabilirler. Varsayılanlar, işlev içinde ilk atamalar olarak uygulanır.
enum FooOptions<'a> {
Height(f64),
Weight(f64),
Name(&'a str),
}
use FooOptions::*;
fn foo(args: &[FooOptions]) {
let mut height = 1.8;
let mut weight = 77.11;
let mut name = "unspecified".to_string();
for opt in args {
match opt {
Height(h) => height = *h,
Weight(w) => weight = *w,
Name(n) => name = n.to_string(),
}
}
println!(" name: {}\nweight: {} kg\nheight: {} m",
name, weight, height);
}
fn main() {
foo( &[ Weight(90.0), Name("Bob") ] );
}
çıktı:
name: Bob
weight: 90 kg
height: 1.8 m