आज हम सीखेंगे कि Solidity की function visibility और contract inheritance को Solana में कैसे समझा जा सकता है। Solidity में function visibility के चार स्तर होते हैं, वे हैं:
- public - contract के अंदर और बाहर दोनों जगह से एक्सेस किया जा सकता है।
- external - केवल contract के बाहर से एक्सेस किया जा सकता है।
- internal - contract के अंदर और inherit करने वाले contracts से एक्सेस किया जा सकता है।
- private - केवल contract के अंदर एक्सेस किया जा सकता है।
चलिए Solana में भी ऐसा ही करते हैं, क्या खयाल है?
Public functions
Day 1 से लेकर आज तक हमने जितने भी functions define किए हैं, वे सभी public functions हैं:
pub fn my_public_function(ctx: Context<Initialize>) -> Result<()> {
// Function logic...
Ok(())
}
Function declaration से पहले pub कीवर्ड जोड़ने से function public हो जाता है।
आप #[program] लेबल वाले module (mod) के अंदर के functions के लिए pub कीवर्ड नहीं हटा सकते हैं। यह compile नहीं होगा।
external और public के बीच के अंतर के बारे में ज्यादा चिंता न करें
Solana प्रोग्राम के लिए अपने स्वयं के public function को कॉल करना आमतौर पर असुविधाजनक होता है। यदि किसी Solana प्रोग्राम में pub function है, तो व्यावहारिक उद्देश्यों के लिए आप इसे Solidity के संदर्भ में external मान सकते हैं।
यदि आप एक ही Solana प्रोग्राम के अंदर किसी public function को कॉल करना चाहते हैं, तो public function को एक internal implementation function के साथ रैप करना और उसे कॉल करना ज्यादा आसान है।
Private और Internal Functions
हालाँकि आप #[program] मैक्रो वाले module के अंदर pub के बिना functions declare नहीं कर सकते, लेकिन आप फ़ाइल के अंदर functions declare कर सकते हैं। निम्नलिखित कोड पर विचार करें:
use anchor_lang::prelude::*;
declare_id!("F26bvRaY1ut3TD1NhrXMsKHpssxF2PAUQ7SjZtnrLkaM");
#[program]
pub mod func_test {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
// -------- calling a "private" function --------
let u = get_a_num();
msg!("{}", u);
Ok(())
}
}
// ------- We declared a non pub function over here -------
fn get_a_num() -> u64 {
2
}
#[derive(Accounts)]
pub struct Initialize {}
यह उम्मीद के मुताबिक रन और लॉग होगा।
यदि आप सरल Solana प्रोग्राम बनाना चाहते हैं तो public और internal functions के बारे में आपको बस इतना ही जानने की आवश्यकता है, लेकिन यदि आप प्रोग्राम के बाहर फ़ाइल में कुछ functions को declare करने के बजाय अपने कोड को बेहतर ढंग से व्यवस्थित करना चाहते हैं, तो आप आगे बढ़ सकते हैं। Rust, और इसलिए Solana में, Solidity की तरह “classes” नहीं होती हैं, क्योंकि Rust ऑब्जेक्ट-ओरिएंटेड नहीं है। इसलिए, “private” और “internal” के बीच के अंतर का Rust में कोई सीधा विकल्प नहीं है।
Rust कोड को व्यवस्थित करने के लिए modules का उपयोग करता है। इन modules के अंदर और बाहर functions की visibility के बारे में Visibility and Privacy section of the Rust docs में अच्छी तरह से चर्चा की गई है, लेकिन हम नीचे अपना खुद का Solana-उन्मुख दृष्टिकोण जोड़ेंगे।
Internal function
इसे प्रोग्राम module के भीतर function को define करके प्राप्त किया जा सकता है और यह सुनिश्चित किया जा सकता है कि यह अपने स्वयं के module और अन्य modules में सुलभ है जहां इसे import या उपयोग किया जाता है। आइए देखें कि यह कैसे करना है:
use anchor_lang::prelude::*;
declare_id!("53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX");
#[program]
pub mod func_visibility {
use super::*;
pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
// Call the internal_function from within its parent module
some_internal_function::internal_function();
Ok(())
}
pub mod some_internal_function {
pub fn internal_function() {
// Internal function logic...
}
}
}
mod do_something {
// Import func_visibility module
use crate::func_visibility;
pub fn some_func_here() {
// Call the internal_function from outside its parent module
func_visibility::some_internal_function::internal_function();
// Do something else...
}
}
#[derive(Accounts)]
pub struct Initialize {}
प्रोग्राम को बिल्ड करने के बाद, यदि आप ./target/idl/func_visibility.json फ़ाइल पर नेविगेट करते हैं, तो आप देखेंगे कि some_internal_function module के भीतर define किया गया function बिल्ड किए गए प्रोग्राम में शामिल नहीं था। यह इंगित करता है कि फ़ंक्शन some_internal_function internal है और इसे केवल प्रोग्राम के भीतर और इसे import या उपयोग करने वाले किसी भी प्रोग्राम में एक्सेस किया जा सकता है।
उपरोक्त उदाहरण से, हम internal_function फ़ंक्शन को उसके “parent” module (func_visibility) के भीतर से और func_visibility module के बाहर एक अलग module (do_something) से भी एक्सेस करने में सक्षम थे।
Private function
किसी विशिष्ट module के भीतर किसी function को define करना और यह सुनिश्चित करना कि वे उस स्कोप के बाहर उजागर नहीं हैं, private visibility प्राप्त करने का एक तरीका है:
use anchor_lang::prelude::*;
declare_id!("53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX");
#[program]
pub mod func_visibility {
use super::*;
pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
// Call the private_function from within its parent module
some_function_function::private_function();
Ok(())
}
pub mod some_function_function {
pub(in crate::func_visibility) fn private_function() {
// Private function logic...
}
}
}
#[derive(Accounts)]
pub struct Initialize {}
pub(in crate::func_visibility) कीवर्ड इंगित करता है कि private_function फ़ंक्शन केवल func_visibility module के भीतर दिखाई देता है।
हम initialize फ़ंक्शन में private_function को सफलतापूर्वक कॉल करने में सक्षम थे क्योंकि initialize फ़ंक्शन func_visibility module के भीतर है। आइए private_function को module के बाहर से कॉल करने का प्रयास करें:
use anchor_lang::prelude::*;
declare_id!("53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX");
#[program]
pub mod func_visibility {
use super::*;
pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
// Call the private_function from within its parent module
some_private_function::private_function();
Ok(())
}
pub mod some_private_function {
pub(in crate::func_visibility) fn private_function() {
// Private function logic...
}
}
}
mod do_something {
// Import func_visibility module
use crate::func_visibility;
pub fn some_func_here() {
// Call the private_function from outside its parent module
func_visibility::some_private_function::private_function()
// Do something...
}
}
#[derive(Accounts)]
pub struct Initialize {}
प्रोग्राम को बिल्ड करें। क्या हुआ? हमें एक एरर मिली:
❌ error[E0624]: associated function private_function is private
यह दर्शाता है कि private_function सार्वजनिक रूप से सुलभ नहीं है और इसे उस module के बाहर से invoke नहीं किया जा सकता है जहां यह visible है। pub visibility कीवर्ड के बारे में अधिक जानने के लिए Rust डॉक्स में visibility and privacy देखें।
Contract Inheritance
Solidity की contract inheritance का सीधा अनुवाद Solana में संभव नहीं है क्योंकि Rust में classes नहीं होती हैं।
हालाँकि, Rust में एक विकल्प यह है कि अलग-अलग modules बनाए जाएँ जो विशिष्ट कार्यक्षमता को define करते हैं और फिर उन modules का उपयोग हमारे मुख्य प्रोग्राम के भीतर किया जाए, जिससे Solidity के contract inheritance के समान कुछ प्राप्त किया जा सके।
किसी अन्य फ़ाइल से modules प्राप्त करना
जैसे-जैसे प्रोग्राम बड़े होते जाते हैं, हम आमतौर पर सब कुछ एक ही फ़ाइल में नहीं रखना चाहते हैं। यहां बताया गया है कि हम लॉजिक को कई फ़ाइलों में कैसे व्यवस्थित कर सकते हैं।
आइए src फ़ोल्डर में calculate.rs नामक एक और फ़ाइल बनाएं और दिए गए कोड को उसमें कॉपी करें।
pub fn add(x: u64, y: u64) -> u64 {
// Return the sum of x and y
x + y
}
यह add फ़ंक्शन x और y का योग लौटाता है।
और इसे, lib.rs में।
use anchor_lang::prelude::*;
// Import `calculate` module or crate
pub mod calculate;
declare_id!("53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX");
#[program]
pub mod func_visibility {
use super::*;
pub fn add_two_numbers(_ctx: Context<Initialize>, x: u64, y: u64) -> Result<()> {
// Call `add` function in calculate.rs
let result = calculate::add(x, y);
msg!("{} + {} = {}", x, y, result);
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize {}
उपरोक्त प्रोग्राम में, हमने पहले बनाए गए calculate module को import किया और add_two_numbers नामक एक फ़ंक्शन declare किया जो दो संख्याओं को जोड़ता है और परिणाम को लॉग करता है। add_two_numbers फ़ंक्शन calculate module में add फ़ंक्शन को कॉल करता है, x और y को arguments के रूप में पास करता है, फिर रिटर्न वैल्यू को result वेरिएबल में स्टोर करता है। msg! मैक्रो उन दो संख्याओं को जिन्हें जोड़ा गया था और उनके परिणाम को लॉग करता है।
Modules का अलग-अलग फ़ाइलें होना ज़रूरी नहीं है
निम्नलिखित उदाहरण calculate.rs के बजाय lib.rs के अंदर एक module declare करता है।
use anchor_lang::prelude::*;
declare_id!("53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX");
#[program]
pub mod func_visibility {
use super::*;
pub fn add_two_numbers(_ctx: Context<Initialize>, x: u64, y: u64) -> Result<()> {
// Call `add` function in calculate.rs
let result = calculate::add(x, y);
msg!("{} + {} = {}", x, y, result);
Ok(())
}
}
mod calculate {
pub fn add(x: u64, y: u64) -> u64 {
// Return the summation of x and y
x + y
}
}
#[derive(Accounts)]
pub struct Initialize {}
यह प्रोग्राम पिछले उदाहरण के समान ही काम करता है, फर्क सिर्फ इतना है कि add फ़ंक्शन lib.rs फ़ाइल में और calculate module के भीतर मौजूद है। इसके अलावा, किसी फ़ंक्शन में pub कीवर्ड जोड़ना महत्वपूर्ण है, क्योंकि यह फ़ंक्शन को सार्वजनिक रूप से सुलभ बनाता है। नीचे दिया गया कोड compile नहीं होगा:
use anchor_lang::prelude::*;
declare_id!("53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX");
#[program]
pub mod func_visibility {
use super::*;
pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
// Call the private-like function
let result2 = do_something::some_func_here();
msg!("The result is {}", result2);
Ok(())
}
}
mod do_something {
// private-like function. It exists in the code, but not everyone can call it
fn some_func_here() -> u64 {
// Do something...
return 20;
}
}
#[derive(Accounts)]
pub struct Initialize {}
Summary
Solidity में, हम function visibility के बारे में बहुत सोचते हैं क्योंकि यह बहुत महत्वपूर्ण है। यहाँ बताया गया है कि Rust में इसके बारे में कैसे विचार करें:
- Public / External Functions: ये ऐसे फ़ंक्शंस हैं जिन्हें प्रोग्राम के भीतर और बाहर दोनों जगह एक्सेस किया जा सकता है। Solana में, declare किए गए सभी फ़ंक्शंस, बाय डिफ़ॉल्ट, public होते हैं।
#[program]ब्लॉक में हर चीज़ को pub declare किया जाना चाहिए। - Internal Functions: ये वे फ़ंक्शंस हैं जिन्हें प्रोग्राम के भीतर और इसे inherit करने वाले प्रोग्राम्स में एक्सेस किया जा सकता है। नेस्टेड pub mod ब्लॉक के अंदर के फ़ंक्शंस बिल्ड किए गए प्रोग्राम में शामिल नहीं होते हैं, लेकिन फिर भी, उन्हें parent module के भीतर या बाहर एक्सेस किया जा सकता है।
- Private Functions: ये वे फ़ंक्शंस हैं जो सार्वजनिक रूप से सुलभ नहीं हैं और उन्हें उनके module के बाहर से invoke नहीं किया जा सकता है। Rust/Solana में private visibility प्राप्त करने के लिए
pub(in crate::<module>)कीवर्ड के साथ एक विशिष्ट module के भीतर एक फ़ंक्शन को define करना शामिल है, जो फ़ंक्शन को केवल उस module के भीतर दृश्यमान बनाता है जिसमें इसे define किया गया था।
Solidity classes के माध्यम से contract inheritance प्राप्त करता है, जो एक ऐसी विशेषता है जो Solana में इस्तेमाल की जाने वाली भाषा Rust में नहीं है। फिर भी, आप Rust modules का उपयोग करके अपने कोड को व्यवस्थित कर सकते हैं।
RareSkills के साथ और जानें
यह ट्यूटोरियल हमारे मुफ़्त Solana course का हिस्सा है।
मूल रूप से 17 फरवरी, 2024 को प्रकाशित