यह ट्यूटोरियल Solidity में सबसे अधिक उपयोग किए जाने वाले सिंटैक्स (syntax) के बारे में बताता है और Rust में इसके समकक्ष (equivalent) को प्रदर्शित करता है।
यदि आप Rust vs Solidity के अंतरों का हाई-लेवल ओवरव्यू (high-level overview) चाहते हैं, तो कृपया लिंक किए गए ट्यूटोरियल को देखें। यह ट्यूटोरियल मानकर चलता है कि आप पहले से ही Solidity जानते हैं, इसलिए यदि आप Solidity से अपरिचित हैं तो कृपया हमारा मुफ्त Solidity tutorial देखें।
tryrust नामक एक नया Solana Anchor प्रोजेक्ट बनाएं और एनवायरनमेंट सेट करें।
Conditional statements
हम कह सकते हैं कि Solidity में किसी विशिष्ट स्थिति (condition) के आधार पर execution के फ्लो को कंट्रोल करने के 2 तरीके हैं:
- If-Else Statements
- Ternary operator
अब आइए ऊपर दिए गए तरीकों को Solidity में देखें, और Solana में उनका अनुवाद (translation) देखें।
If-Else Statements
Solidity में:
function ageChecker(uint256 age) public pure returns (string memory) {
if (age >= 18) {
return "You are 18 years old or above";
} else {
return "You are below 18 years old";
}
}
Solana में, lib.rs में age_checker नामक एक नया फ़ंक्शन जोड़ें:
pub fn age_checker(ctx: Context<Initialize>, age: u64) -> Result<()> {
if age >= 18 {
msg!("You are 18 years old or above");
} else {
msg!("You are below 18 years old");
}
Ok(())
}
ध्यान दें कि कंडीशन age >= 18 में कोष्ठक (parenthesis) नहीं हैं — if स्टेटमेंट्स के लिए वे वैकल्पिक (optional) हैं।
टेस्ट करने के लिए, ./tests/tryrust.ts में एक और it ब्लॉक जोड़ें:
it("Age checker", async () => {
// Add your test here.
const tx = await program.methods.ageChecker(new anchor.BN(35)).rpc();
console.log("Your transaction signature", tx);
});
टेस्ट चलाने के बाद हमें निम्नलिखित लॉग्स मिलने चाहिए:
Transaction executed in slot 77791:
Signature: 2Av18ej2YjkRhzybbccPpwEtkw73VcBpDPZgC9iKrmf6mvwbqjA517garhrntWxKAM1ULL2eAv5vDWJ3SjnFZq6j
Status: Ok
Log Messages:
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX invoke [1]
Program log: Instruction: AgeChecker
Program log: You are 18 years old or above
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX consumed 440 of 200000 compute units
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX success
Ternary operator
Solidity में किसी वेरिएबल को if-else स्टेटमेंट असाइन करना:
function ageChecker(uint256 age) public pure returns (bool a) {
a = age % 2 == 0 ? true : false;
}
Solana में ऐसा करने के लिए, हम मूल रूप से बस एक if-else स्टेटमेंट को किसी वेरिएबल में असाइन करते हैं। नीचे दिया गया Solana प्रोग्राम ऊपर वाले के ही समान है:
pub fn age_checker(ctx: Context<Initialize>, age: u64) -> Result<()> {
let result = if age >= 18 {"You are 18 years old or above"} else { "You are below 18 years old" };
msg!("{:?}", result);
Ok(())
}
ध्यान दें कि Rust में Ternary Operator के उदाहरण में, if/else ब्लॉक एक सेमी-कोलन (semi-colon) के साथ समाप्त होता है क्योंकि इसे एक वेरिएबल में असाइन किया जा रहा है।
यह भी ध्यान दें कि आंतरिक (inner) वैल्यूज़ के अंत में सेमी-कोलन नहीं होता है क्योंकि इसे वेरिएबल के रिटर्न वैल्यू के रूप में वापस किया जा रहा है, ठीक उसी तरह जैसे आप Ok(()) के बाद सेमी-कोलन नहीं लगाते हैं क्योंकि यह एक एक्सप्रेशन (expression) है, स्टेटमेंट नहीं।
यदि age सम (even) है तो प्रोग्राम true लॉग करता है, अन्यथा false:
Transaction executed in slot 102358:
Signature: 2zohZKhY56rLb7myFs8kabdwULJALENyvyFS5LC6yLM264BnkwsThMnotHNAssJbQEzQpmK4yd3ozs3zhG3GH1Gx
Status: Ok
Log Messages:
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX invoke [1]
Program log: Instruction: AgeChecker
Program log: true
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX consumed 792 of 200000 compute units
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX success
Rust में एक और शक्तिशाली कंट्रोल फ्लो कंस्ट्रक्ट (control flow construct) है जिसे match कहा जाता है। आइए नीचे match का उपयोग करने का एक उदाहरण देखें:
pub fn age_checker(ctx: Context<Initialize>, age: u64) -> Result<()> {
match age {
1 => {
// Code block executed if age equals 1
msg!("The age is 1");
},
2 | 3 => {
// Code block executed if age equals 2 or 3
msg!("The age is either 2 or 3");
},
4..=6 => {
// Code block executed if age is in the
// range 4 to 6 (inclusive)
msg!("The age is between 4 and 6");
},
_ => {
// Code block executed for any other age
msg!("The age is something else");
}
}
Ok(())
}
For Loops
जैसा कि हम जानते हैं, for लूप रेंजेज़ (ranges), कलेक्शंस (collections), और अन्य इटरेबल ऑब्जेक्ट्स (iterable objects) पर लूप करने की अनुमति देता है और इसे Solidity में इस प्रकार लिखा जाता है:
function loopOverSmth() public {
for (uint256 i=0; i < 10; i++) {
// do something...
}
}
Solana (Rust) में इसका समकक्ष (equivalent) यह है:
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
for i in 0..10 {
// do something...
}
Ok(())
}
हाँ, यह इतना ही सरल है, लेकिन हम कस्टम स्टेप (custom step) के साथ किसी रेंज पर इटरेट (iterate) कैसे करते हैं? Solidity में अपेक्षित व्यवहार (intended behavior) यहाँ दिया गया है:
function loopOverSmth() public {
for (uint256 i=0; i < 10; i+=2) {
// do something...
// Increment i by 2
}
}
step_by का उपयोग करके Solana में इसका समकक्ष यहाँ दिया गया है:
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
for i in (0..10).step_by(2) {
// do something...
msg!("{}", i);
}
Ok(())
}
टेस्ट को चलाने पर, हमारे पास निम्नलिखित लॉग्स होने चाहिए:
Transaction executed in slot 126442:
Signature: 3BSPA11TZVSbF8krjMnge1fgwNsL9odknD2twAsDeYEF39AzaJy1c5TmFCt6LEzLtvWnjzx7VyFKJ4VT1KQBpiwm
Status: Ok
Log Messages:
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX invoke [1]
Program log: Instruction: Initialize
Program log: 0
Program log: 2
Program log: 4
Program log: 6
Program log: 8
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX consumed 2830 of 200000 compute units
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX success
Arrays और Vectors
एरे सपोर्ट (array support) के मामले में Rust, Solidity से अलग है। जहाँ Solidity में फिक्स्ड और डायनामिक एरेज़ दोनों के लिए नेटिव सपोर्ट है, वहीं Rust में केवल फिक्स्ड एरेज़ के लिए बिल्ट-इन सपोर्ट है। यदि आपको डायनामिक-लेंथ वाली लिस्ट चाहिए, तो वेक्टर (vector) का उपयोग करें।
अब, आइए कुछ ऐसे उदाहरण देखें जो यह प्रदर्शित करते हैं कि फिक्स्ड और डायनामिक एरेज़ दोनों को कैसे डिक्लेयर (declare) और इनिशियलाइज़ (initialize) किया जाए।
Fixed array
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
// Declare an array of u32 with a fixed size of 5
let my_array: [u32; 5] = [10, 20, 30, 40, 50];
// Accessing elements of the array
let first_element = my_array[0];
let third_element = my_array[2];
// Declare a mutable array of u32 with a fixed size of 3
let mut mutable_array: [u32; 3] = [100, 200, 300];
// Change the second element from 200 to 250
mutable_array[1] = 250;
// Rest of your program's logic
Ok(())
}
Dynamic array
Solana में डायनामिक एरे को सिम्युलेट (simulate) करने की एक विधि में Rust स्टैण्डर्ड लाइब्रेरी (standard library) से Vec (Vector) का उपयोग करना शामिल है। नीचे एक उदाहरण दिया गया है:
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
// Declare a dynamic array-like structure using Vec
let mut dynamic_array: Vec<u32> = Vec::new();
// Add elements to the dynamic array
dynamic_array.push(10);
dynamic_array.push(20);
dynamic_array.push(30);
// Accessing elements of the dynamic array
let first_element = dynamic_array[0];
let third_element = dynamic_array[2];
// Rest of your program's logic
msg!("Third element = {}", third_element);
Ok(())
}
dynamic_array वेरिएबल को म्यूटेबल (mut) के रूप में डिक्लेयर किया जाना चाहिए ताकि म्यूटेटिंग (mutating) (जैसे push, pop, किसी इंडेक्स पर ओवरराइड करना आदि) की अनुमति मिल सके।
टेस्ट चलाने के बाद प्रोग्राम को यह लॉग करना चाहिए:
Transaction executed in slot 195373:
Signature: 4113irrcBsFbNaiZia5c84yfJpS4Hn4H1QawfUSHYoPuuQPj22JnVFtDMHmZDFkQ3vK15SrDUSTakh5fT4N8UVRf
Status: Ok
Log Messages:
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX invoke [1]
Program log: Instruction: Initialize
Program log: Third element = 30
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX consumed 1010 of 200000 compute units
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX success
Mappings
Solidity के विपरीत, Solana में बिल्ट-इन मैपिंग डेटा स्ट्रक्चर (mapping data structure) का अभाव है। हालाँकि, हम Rust स्टैण्डर्ड लाइब्रेरी से HashMap टाइप का उपयोग करके Solana में की-वैल्यू मैपिंग्स (key-value mappings) कार्यक्षमता को रेप्लिकेट (replicate) कर सकते हैं। EVM चेन्स के विपरीत, जो मैप हम यहाँ प्रदर्शित कर रहे हैं वह मेमोरी (memory) में है, स्टोरेज (storage) में नहीं। EVM चेन्स में इन-मेमोरी हैश मैप्स (in-memory hash maps) नहीं होते हैं। हम बाद में Solana के लिए स्टोरेज में मैपिंग्स का प्रदर्शन करेंगे।
आइए देखें कि Solana में मैपिंग बनाने के लिए HashMap का उपयोग कैसे करें। दिए गए कोड स्निपेट को lib.rs फ़ाइल में कॉपी और पेस्ट करें, और याद रखें कि प्रोग्राम ID को अपने खुद के ID से बदल लें:
use anchor_lang::prelude::*;
declare_id!("53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX");
#[program]
pub mod tryrust {
use super::*;
// Import HashMap library
use std::collections::HashMap;
pub fn initialize(ctx: Context<Initialize>, key: String, value: String) -> Result<()> {
// Initialize the mapping
let mut my_map = HashMap::new();
// Add a key-value pair to the mapping
my_map.insert(key.to_string(), value.to_string());
// Log the value corresponding to a key from the mapping
msg!("My name is {}", my_map[&key]);
Ok(())
}
}
my_map वेरिएबल को भी म्यूटेबल बनाया गया है ताकि हम इसे एडिट कर सकें (यानी, की → वैल्यू पेयर्स (key → value pairs) को जोड़/हटा सकें)। क्या आपने यह भी ध्यान दिया कि हमने HashMap लाइब्रेरी को कैसे इम्पोर्ट किया?
चूँकि initialize फ़ंक्शन दो पैरामीटर्स (parameters) प्राप्त करता है, इसलिए टेस्ट को भी अपडेट करने की आवश्यकता है:
it("Is initialized!", async () => {
// Add your test here.
const tx = await program.methods.initialize("name", "Bob").rpc();
console.log("Your transaction signature", tx);
});
जब हम टेस्ट रन करते हैं, तो हमें निम्नलिखित लॉग दिखाई देता है:
Transaction executed in slot 216142:
Signature: 5m4Cx26jaYT3c6YeJbLMDHppvki4Kmu3zTDMgk8Tao9v8b9sH7WgejETzymnHuUfr4hY25opptqniBuwDpncbnB9
Status: Ok
Log Messages:
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX invoke [1]
Program log: Instruction: Initialize
Program log: My name is Bob
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX consumed 2634 of 200000 compute units
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX success
Structs
Solidity और Solana में, स्ट्रक्ट्स (structs) का उपयोग कस्टम डेटा स्ट्रक्चर्स (custom data structures) को परिभाषित करने के लिए किया जाता है जो कई फ़ील्ड्स (fields) को होल्ड कर सकते हैं। आइए Solidity और Solana दोनों में एक स्ट्रक्ट का उदाहरण देखें।
Solidity में:
contract SolidityStructs {
// Defining a struct in Solidity
struct Person {
string my_name;
uint256 my_age;
}
// Creating an instance of the struct
Person person1;
function initPerson1(string memory name, uint256 age) public {
// Accessing and modifying struct fields
person1.my_name = name;
person1.my_age = age;
}
}
Solana में इसकी 1-1 समानता (correspondence):
pub fn initialize(_ctx: Context<Initialize>, name: String, age: u64) -> Result<()> {
// Defining a struct in Solana
struct Person {
my_name: String,
my_age: u64,
}
// Creating an instance of the struct
let mut person1: Person = Person {
my_name: name,
my_age: age,
};
msg!("{} is {} years old", person1.my_name, person1.my_age);
// Accessing and modifying struct fields
person1.my_name = "Bob".to_string();
person1.my_age = 18;
msg!("{} is {} years old", person1.my_name, person1.my_age);
Ok(())
}
Exercise: initialize फ़ंक्शन में दो आर्गुमेंट्स (arguments) Alice और 20 पास करने के लिए टेस्ट फ़ाइल को अपडेट करें और टेस्ट चलाएं, आपको निम्नलिखित लॉग्स मिलने चाहिए:
Transaction executed in slot 324406:
Signature: 2XBQKJLpkJbVuuonqzirN9CK5dNKnuu5NqNCGTGgQovWBfrdjRcVeckDmqtzyEPe4PP8xSN8vf2STNxWygE4BPZN
Status: Ok
Log Messages:
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX invoke [1]
Program log: Instruction: Initialize
Program log: Alice is 20 years old
Program log: Bob is 18 years old
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX consumed 2601 of 200000 compute units
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX success
दिए गए कोड स्निपेट में, Solidity इम्प्लीमेंटेशन स्ट्रक्ट के इंस्टेंस (instance) को स्टोरेज (storage) में स्टोर करता है, जबकि Solana इम्प्लीमेंटेशन में, सब कुछ initialize फ़ंक्शन में हुआ और ऑन-चेन (on-chain) कुछ भी स्टोर नहीं किया गया। स्टोरेज पर बाद के ट्यूटोरियल में चर्चा की जाएगी।
Rust में Constants
Rust में कॉन्स्टेंट वेरिएबल (constant variable) डिक्लेयर करना सीधा और आसान है। let कीवर्ड (keyword) का उपयोग करने के बजाय, const कीवर्ड का उपयोग करें। इन्हें #[program] ब्लॉक के बाहर भी डिक्लेयर किया जा सकता है।
use anchor_lang::prelude::*;
declare_id!("EiR8gcMCX11tYMRfoZ2vyheZsZ2NvdUTvYrRAUvTtYnL");
// *** CONSTANT DECLARED HERE ***
const MEANING_OF_LIFE_AND_EXISTENCE: u64 = 42;
#[program]
pub mod tryrust {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
msg!(&format!("Answer to the ultimate question: {}", MEANING_OF_LIFE_AND_EXISTENCE)); // new line here
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize {}
usize टाइप और casting
ज्यादातर समय हम मान सकते हैं कि Solana में अनसाइंड इंटिजर्स (unsigned integers) u64 टाइप के होते हैं, लेकिन किसी लिस्ट की लंबाई (length) मापते समय एक अपवाद (exception) है: यह usize टाइप का होगा। आपको वेरिएबल को कास्ट (cast) करने की आवश्यकता होगी जैसा कि निम्नलिखित Rust कोड प्रदर्शित करता है:
use anchor_lang::prelude::*;
declare_id!("EiR8gcMCX11tYMRfoZ2vyheZsZ2NvdUTvYrRAUvTtYnL");
#[program]
pub mod usize_example {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let mut dynamic_array: Vec<u32> = Vec::from([1,2,3,4,5,6]);
let len = dynamic_array.len(); // this has type usize
let another_var: u64 = 5; // this has type u64
let len_plus_another_var = len as u64 + another_var;
msg!("The result is {}", len_plus_another_var);
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize {}
Try Catch
Rust में try catch नहीं होता है। फेलियर्स (failures) में एरर्स (errors) रिटर्न करने की अपेक्षा की जाती है (जैसे कि हमने Solana रिवर्ट्स (reverts) और एरर्स पर अपने ट्यूटोरियल में किया था) या नॉन-रिकवरेबल एरर्स (non-recoverable errors) के लिए पैनिक (panic) की अपेक्षा की जाती है।
Exercise: एक ऐसा Solana / Rust प्रोग्राम लिखें जो u64 का एक वेक्टर (vector) लेता है, इसके माध्यम से लूप (loop) करता है, और सभी सम संख्याओं (even numbers) को एक अन्य वेक्टर में पुश (push) करता है, फिर नए वेक्टर को प्रिंट करता है।
RareSkills के साथ और जानें
यह ट्यूटोरियल हमारे मुफ्त Solana course का हिस्सा है।
मूल रूप से 13 फरवरी, 2024 को प्रकाशित