खोज…
वाक्य - विन्यास
- संरचना Foo {फ़ील्ड 1: टाइप 1, फ़ील्ड 2: टाइप 2}
- चलो फू = फू {फ़ील्ड 1: टाइप 1 :: नया (), फ़ील्ड 2: टाइप 2 :: नया ()};
- संरचना बार (टाइप 1, टाइप 2); // ट्यूपल प्रकार
- चलो _ = बार (टाइप 1 :: नया (), टाइप 2 :: नया ());
- संरचना बाज; // इकाई की तरह प्रकार
- चलो _ = बाज;
- Foo {फ़ील्ड 1, ..} = फू; / / फ़ील्ड 1 पैटर्न मिलान द्वारा निकालें
- Foo {फ़ील्ड 1: x, ..} = फू; // एक्स के रूप में फ़ील्ड 1 निकालें
- let foo2 = Foo {field1: Type1 :: new (), .. foo}; // मौजूदा से निर्माण
- इम्पू फू {fn फिडेल (एंड सेल्फ) {}} // फू के लिए उदाहरण विधि घोषित करें
- इम्पू फू {एफएन ट्वीक (और म्युट सेल्फ) {}} // फू के लिए म्यूटेबल इंस्टेंस विधि घोषित करें
- इम्पू फू {fn डबल (सेल्फ) {}} // फू के लिए खुद की इंस्टेंस इंस्टेंस विधि घोषित करें
- इम्पू फ़ू {fn new () {}} // फ़ू के लिए संबद्ध विधि की घोषणा करें
संरचनाओं को परिभाषित करना
जंग में संरचनाएं का उपयोग कर परिभाषित कर रहे हैं struct
कीवर्ड। संरचना का सबसे आम रूप में नामित क्षेत्रों का एक सेट होता है:
struct Foo {
my_bool: bool,
my_num: isize,
my_string: String,
}
उपरोक्त तीन क्षेत्रों के साथ एक struct
घोषणा करता है: my_bool
, my_num
, और my_string
, क्रमशः bool
, isize
, और String
।
रस्ट में struct
एस बनाने का एक और तरीका है एक ट्यूपल स्ट्रक्चर बनाना:
struct Bar (bool, isize, String);
यह एक नए प्रकार को परिभाषित करता है, Bar
, जिसमें तीन अनाम फ़ील्ड हैं, उस क्रम में bool
, isize
, और String
। इसे न्यूटाइप पैटर्न के रूप में जाना जाता है, क्योंकि यह एक विशेष प्रकार के लिए प्रभावी रूप से एक नया "नाम" पेश करता है। हालाँकि, यह type
कीवर्ड के उपयोग से निर्मित उपनामों की तुलना में अधिक शक्तिशाली तरीके से करता है; Bar
यहां पूरी तरह से कार्यात्मक प्रकार है, जिसका अर्थ है कि आप इसके लिए अपने तरीके लिख सकते हैं (नीचे)।
अंत में, बिना फ़ील्ड वाले struct
को घोषित करें, जिसे इकाई जैसी संरचना कहा जाता है:
struct Baz;
यह मॉकिंग या टेस्टिंग के लिए उपयोगी हो सकता है (जब आप किसी विशेषता को तुच्छ रूप से लागू करना चाहते हैं), या एक मार्कर प्रकार के रूप में। सामान्य तौर पर, हालांकि, आपको कई यूनिट जैसी संरचना में आने की संभावना नहीं है।
ध्यान दें कि Rust में struct
क्षेत्र डिफ़ॉल्ट रूप से सभी निजी हैं - अर्थात, वे मॉड्यूल के बाहर कोड से एक्सेस नहीं किए जा सकते हैं जो प्रकार को परिभाषित करता है। आप उस क्षेत्र को सार्वजनिक रूप से सुलभ बनाने के लिए pub
कीवर्ड के साथ एक फ़ील्ड को उपसर्ग कर सकते हैं। इसके अलावा, struct
प्रकार स्वयं निजी है। अन्य मॉड्यूलों को प्रकार उपलब्ध कराने के लिए, pub
साथ struct
परिभाषा को भी उपसर्ग करना चाहिए:
pub struct X {
my_field: bool,
pub our_field: bool,
}
संरचना मूल्यों का निर्माण और उपयोग करना
निम्नलिखित struct
परिभाषाओं पर विचार करें:
struct Foo {
my_bool: bool,
my_num: isize,
my_string: String,
}
struct Bar (bool, isize, String);
struct Baz;
इन प्रकारों के लिए नए संरचना मूल्यों का निर्माण सीधा है:
let foo = Foo { my_bool: true, my_num: 42, my_string: String::from("hello") };
let bar = Bar(true, 42, String::from("hello"));
let baz = Baz;
एक संरचना का उपयोग क्षेत्रों का उपयोग .
:
assert_eq!(foo.my_bool, true);
assert_eq!(bar.0, true); // tuple structs act like tuples
एक संरचना के लिए एक परिवर्तनशील बंधन अपने क्षेत्रों को उत्परिवर्तित कर सकता है:
let mut foo = foo;
foo.my_bool = false;
let mut bar = bar;
bar.0 = false;
Rust के पैटर्न-मिलान क्षमताओं का उपयोग किसी struct
अंदर struct
लिए भी किया जा सकता है:
// creates bindings mb, mn, ms with values of corresponding fields in foo
let Foo { my_bool: mb, my_num: mn, my_string: ms } = foo;
assert_eq!(mn, 42);
// .. allows you to skip fields you do not care about
let Foo { my_num: mn, .. } = foo;
assert_eq!(mn, 42);
// leave out `: variable` to bind a variable by its field name
let Foo { my_num, .. } = foo;
assert_eq!(my_num, 42);
या रस्ट के सिंटैक्स के साथ "टेम्पलेट" के रूप में दूसरी संरचना का उपयोग करके एक संरचना बनाएं:
let foo2 = Foo { my_string: String::from("world"), .. foo };
assert_eq!(foo2.my_num, 42);
संरचना के तरीके
एक struct पर तरीकों घोषित करने के लिए (यानी, कार्यों कि "पर" कहा जा सकता है struct
, या उस के मूल्यों struct
प्रकार), एक बनाने impl
ब्लॉक:
impl Foo {
fn fiddle(&self) {
// "self" refers to the value this method is being called on
println!("fiddling {}", self.my_string);
}
}
// ...
foo.fiddle(); // prints "fiddling hello"
&self
यहां struct Foo
उदाहरण के लिए एक अपरिवर्तनीय संदर्भ को इंगित करता है struct Foo
fiddle
विधि को लागू करने के लिए आवश्यक है। यदि हम उदाहरण को संशोधित करना चाहते हैं (जैसे कि इसके किसी एक क्षेत्र को बदलना), तो हम इसके बजाय एक &mut self
(जैसे, एक परस्पर संदर्भ) लेंगे:
impl Foo {
fn tweak(&mut self, n: isize) {
self.my_num = n;
}
}
// ...
foo.tweak(43);
assert_eq!(foo.my_num, 43);
अंत में, हम भी इस्तेमाल कर सकते हैं self
(एक की कमी ध्यान दें &
रिसीवर के रूप में)। यह कॉल करने वाले के स्वामित्व की आवृत्ति की आवश्यकता है, और विधि को कॉल करते समय आवृत्ति को स्थानांतरित करने का कारण होगा। यह उपयोगी हो सकता है अगर हम उपभोग करना, नष्ट करना, या अन्यथा मौजूदा उदाहरण को पूरी तरह से बदलना चाहते हैं। इस तरह के उपयोग-मामले का एक उदाहरण "चैनिंग" तरीके प्रदान करना है:
impl Foo {
fn double(mut self) -> Self {
self.my_num *= 2;
self
}
}
// ...
foo.my_num = 1;
assert_eq!(foo.double().double().my_num, 4);
ध्यान दें कि हमने म्यूट के साथ self
को भी उपसर्ग किया है ताकि हम इसे फिर से वापस करने से पहले self
को mut
सकें। double
विधि का रिटर्न प्रकार भी कुछ स्पष्टीकरण का वारंट करता है। एक impl
ब्लॉक के अंदर Self
उस प्रकार को संदर्भित करता है जो impl
इस मामले में लागू होता है ( Foo
)। यहां, यह ज्यादातर प्रकार के हस्ताक्षर को फिर से टाइप करने से बचने के लिए एक उपयोगी शॉर्टहैंड है, लेकिन लक्षणों में, इसका उपयोग अंतर्निहित प्रकार को संदर्भित करने के लिए किया जा सकता है जो किसी विशेष लक्षण को लागू करता है।
संबंधित struct
को घोषित करने के लिए (आमतौर पर अन्य भाषाओं में "क्लास विधि" के रूप में संदर्भित) एक struct
बस self
तर्क को छोड़ दें। इस तरह के तरीकों को struct
प्रकार पर कहा जाता है, इसके उदाहरण पर नहीं:
impl Foo {
fn new(b: bool, n: isize, s: String) -> Foo {
Foo { my_bool: b, my_num: n, my_string: s }
}
}
// ...
// :: is used to access associated members of the type
let x = Foo::new(false, 0, String::from("nil"));
assert_eq!(x.my_num, 0);
ध्यान दें कि संरचना विधियों को केवल वर्तमान मॉड्यूल में घोषित किए गए प्रकारों के लिए परिभाषित किया जा सकता है। इसके अलावा, खेतों की तरह, सभी संरचना विधियां डिफ़ॉल्ट रूप से निजी हैं, और इस प्रकार केवल एक ही मॉड्यूल में कोड द्वारा बुलाया जा सकता है। आप उन्हें कहीं से कॉल करने योग्य बनाने के लिए pub
कीवर्ड के साथ परिभाषाओं को उपसर्ग कर सकते हैं।
सामान्य संरचनाएँ
संरचनाओं को एक या अधिक प्रकार के मापदंडों पर सामान्य बनाया जा सकता है। इन प्रकारों को संदर्भित किया जाता है <>
जब प्रकार का संदर्भ दिया जाता है:
struct Gen<T> {
x: T,
z: isize,
}
// ...
let _: Gen<bool> = Gen{x: true, z: 1};
let _: Gen<isize> = Gen{x: 42, z: 2};
let _: Gen<String> = Gen{x: String::from("hello"), z: 3};
अल्पविराम का उपयोग करके कई प्रकार दिए जा सकते हैं:
struct Gen2<T, U> {
x: T,
y: U,
}
// ...
let _: Gen2<bool, isize> = Gen2{x: true, y: 42};
प्रकार पैरामीटर प्रकार का एक हिस्सा है, इसलिए एक ही आधार प्रकार के दो चर, लेकिन विभिन्न मापदंडों के साथ, विनिमेय नहीं हैं:
let mut a: Gen<bool> = Gen{x: true, z: 1};
let b: Gen<isize> = Gen{x: 42, z: 2};
a = b; // this will not work, types are not the same
a.x = 42; // this will not work, the type of .x in a is bool
यदि आप एक फ़ंक्शन लिखना चाहते हैं जो किसी भी प्रकार के पैरामीटर असाइनमेंट की परवाह किए बिना एक struct
स्वीकार करता है, तो उस फ़ंक्शन को भी सामान्य बनाने की आवश्यकता होगी:
fn hello<T>(g: Gen<T>) {
println!("{}", g.z); // valid, since g.z is always an isize
}
लेकिन क्या होगा अगर हम एक फ़ंक्शन लिखना चाहते हैं जो हमेशा gx
प्रिंट कर सकता है? हमें T
को एक प्रकार का होना प्रतिबंधित करना चाहिए जिसे प्रदर्शित किया जा सकता है। हम इसे प्रकार सीमा के साथ कर सकते हैं:
use std::fmt;
fn hello<T: fmt::Display>(g: Gen<T>) {
println!("{} {}", g.x, g.z);
}
hello
फंक्शन अब केवल Gen
इंस्टेंस के लिए परिभाषित किया जाता है, जिसका T
टाइप fmt::Display
। यदि हमने उदाहरण के लिए एक Gen<(bool, isize)>
में पास करने की कोशिश की, तो कंपाइलर शिकायत करेगा कि hello
उस प्रकार से परिभाषित नहीं है।
हम यह भी के प्रकार के मानकों के आधार पर सीधे प्रकार सीमा का उपयोग कर सकते struct
संकेत मिलता है कि आप केवल उस का निर्माण कर सकते struct
कुछ प्रकार के लिए:
use std::hash::Hash;
struct GenB<T: Hash> {
x: T,
}
किसी भी फ़ंक्शन जो एक GenB
तक पहुंच है, अब जानता है कि x
के प्रकार Hash
लागू करता है, और इस प्रकार वे कॉल कर सकते हैं। .x.hash()
। एक ही पैरामीटर के लिए कई प्रकार की सीमाएं उन्हें +
से अलग करके दी जा सकती हैं।
फ़ंक्शंस के लिए समान, where
कीवर्ड का उपयोग करके <>
बाद प्रकार सीमा रखी जा सकती है:
struct GenB<T> where T: Hash {
x: T,
}
इसका एक ही अर्थ है, लेकिन जब आपके पास जटिल सीमा होती है, तो हस्ताक्षर को पढ़ना और प्रारूपित करना आसान बना सकता है।
प्रकार पैरामीटर struct
तरीकों और संबंधित तरीकों के लिए भी उपलब्ध हैं:
// note the <T> parameter for the impl as well
// this is necessary to say that all the following methods only
// exist within the context of those type parameter assignments
impl<T> Gen<T> {
fn inner(self) -> T {
self.x
}
fn new(x: T) -> Gen<T> {
Gen{x: x}
}
}
यदि आपके पास Gen
के T
पर प्रकार की सीमाएं हैं, तो उन्हें भी impl
प्रकार के सीमा में परिलक्षित होना चाहिए। आप यह भी कर सकते हैं impl
कहना है कि किसी दिए गए विधि केवल तभी प्रकार को संतुष्ट करता है एक विशेष संपत्ति मौजूद है सीमा तंग:
impl<T: Hash + fmt::Display> Gen<T> {
fn show(&self) {
println!("{}", self.x);
}
}
// ...
Gen{x: 42}.show(); // works fine
let a = Gen{x: (42, true)}; // ok, because (isize, bool): Hash
a.show(); // error: (isize, bool) does not implement fmt::Display