क्या एक डिफ़ॉल्ट तर्क के साथ फ़ंक्शन बनाने के लिए रस्ट में यह संभव है?
fn add(a: int = 1, b: int = 2) { a + b }
क्या एक डिफ़ॉल्ट तर्क के साथ फ़ंक्शन बनाने के लिए रस्ट में यह संभव है?
fn add(a: int = 1, b: int = 2) { a + b }
Option
और स्पष्ट रूप से पास करना होगा None
।
जवाबों:
नहीं, यह वर्तमान में नहीं है। मुझे लगता है कि संभावना है कि यह अंततः लागू हो जाएगा, लेकिन वर्तमान में इस स्थान में कोई सक्रिय काम नहीं है।
यहां कार्यरत विशिष्ट तकनीक विभिन्न नामों और हस्ताक्षरों के साथ कार्यों या विधियों का उपयोग करना है।
चूंकि डिफ़ॉल्ट तर्क समर्थित नहीं हैं, इसलिए आप एक समान व्यवहार का उपयोग कर सकते हैं Option<T>
fn add(a: Option<i32>, b: Option<i32>) -> i32 {
a.unwrap_or(1) + b.unwrap_or(2)
}
यह डिफ़ॉल्ट मान और फ़ंक्शन को केवल एक बार (प्रत्येक कॉल के बजाय) कोडित करने के उद्देश्य को पूरा करता है, लेकिन निश्चित रूप से टाइप करने के लिए एक पूरी बहुत अधिक है। फ़ंक्शन कॉल ऐसा दिखेगा add(None, None)
, जिसे आप अपने दृष्टिकोण के आधार पर पसंद कर सकते हैं या नहीं।
यदि आप तर्क सूची में कुछ भी नहीं टाइप करते हुए देखते हैं क्योंकि कोडर संभावित रूप से एक विकल्प बनाना भूल जाता है, तो यहां बड़ा फायदा खोजबीन में है; फोन करने वाला स्पष्ट रूप से कह रहा है कि वे आपके डिफ़ॉल्ट मूल्य के साथ जाना चाहते हैं, और यदि वे कुछ भी नहीं डालते हैं, तो उन्हें एक संकलन त्रुटि मिलेगी। इसे टाइपिंग समझें add(DefaultValue, DefaultValue)
।
आप एक मैक्रो का उपयोग भी कर सकते हैं:
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);
दो समाधानों के बीच बड़ा अंतर यह है कि "विकल्प" -al तर्कों के साथ यह लिखना पूरी तरह से मान्य है add(None, Some(4))
, लेकिन मैक्रो पैटर्न से मेल खाने से आप नहीं कर सकते (यह पायथन के डिफ़ॉल्ट तर्क नियमों के समान है)।
आप "तर्क" संरचना और From
/ Into
लक्षण का भी उपयोग कर सकते हैं:
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)));
}
यह विकल्प स्पष्ट रूप से बहुत अधिक कोड है, लेकिन मैक्रो डिज़ाइन के विपरीत यह टाइप सिस्टम का उपयोग करता है जिसका अर्थ है कि कंपाइलर त्रुटियां आपके लाइब्रेरी / एपीआई उपयोगकर्ता के लिए अधिक सहायक होंगी। यह भी उपयोगकर्ताओं को अपने स्वयं के From
कार्यान्वयन करने की अनुमति देता है यदि यह उनके लिए उपयोगी है।
नहीं, Rust डिफ़ॉल्ट फंक्शन आर्ग्युमेंट्स का समर्थन नहीं करता है। आपको अलग-अलग तरीकों को अलग-अलग नामों से परिभाषित करना होगा। कोई फ़ंक्शन ओवरलोडिंग भी नहीं है, क्योंकि जंग प्रकारों को प्राप्त करने के लिए फ़ंक्शन नाम का उपयोग करती है (फ़ंक्शन ओवरलोडिंग के लिए इसके विपरीत की आवश्यकता होती है)।
स्ट्रक्चर इनिशियलाइज़ेशन के मामले में आप इस तरह से स्ट्रक्चर अपडेट सिंटैक्स का उपयोग कर सकते हैं:
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);
}
[अनुरोध पर, मैंने एक नकली प्रश्न से इस उत्तर को पार कर दिया]
जंग डिफ़ॉल्ट फ़ंक्शन तर्कों का समर्थन नहीं करती है, और मुझे विश्वास नहीं है कि इसे भविष्य में लागू किया जाएगा। इसलिए मैंने इसे स्थूल रूप में लागू करने के लिए एक proc_macro युगल लिखा ।
उदाहरण के लिए:
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);
}
यदि आप 1.12 रस्ट या बाद का उपयोग कर रहे हैं, तो आप कम से कम फ़ंक्शन तर्कों को उपयोग करने में आसान बना सकते हैं Option
और 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);
}
एक और तरीका यह हो सकता है कि वैरिएंट के रूप में वैकल्पिक परम के साथ एक एनम घोषित किया जाए, जिसे प्रत्येक विकल्प के लिए सही प्रकार लेने के लिए पैरामीटर किया जा सकता है। फ़ंक्शन को एनम वेरिएंट की एक वैरिएबल लंबाई स्लाइस लेने के लिए लागू किया जा सकता है। वे किसी भी क्रम और लंबाई में हो सकते हैं। फ़ंक्शन को प्रारंभिक असाइनमेंट के रूप में डिफ़ॉल्ट रूप से कार्यान्वित किया जाता है।
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") ] );
}
उत्पादन:
name: Bob
weight: 90 kg
height: 1.8 m