مصاحبهای با Anders Hejlsberg
Database Engineering Complete Course | DBMS Complete Course
In this program, you’ll learn:
Core techniques and methods to structure and manage databases.
Advanced techniques to write database driven applications and advanced data modeling concepts.
MySQL database management system (DBMS) and data creation, querying and manipulation.
How to code and use Python Syntax
How to prepare for technical interviews for database engineer roles.
Pinvoke for C# .NET Framework complete tutorial - May 2023 - 92418487
Complete course. How to expose to C# via pinvoke functions with C programming language signatures exported from DLLs. Use DependenciesGui.exe in order to see the functions exported by win32 API DLLs. Use the website pinvoke.net. How to write C# signatures for C programming language structs, enums, constants. How to wrap pinvoke method signatures in C# idiomatic methods.
DSL چیست؟
Fast and simple Node.js version manager, built in Rust
Cross-platform support (macOS, Windows, Linux)
Single file, easy installation, instant startup
Built with speed in mind
Works with .node-version
and .nvmrc
files
Deno؛ پروژهی جدید خالق Node.js
Static Memory
حافظهی static برای ذخیرهی باینریهای برنامه، متغیرهای استاتیک و حروف رشتهای (در Rust) استفاده میشود. اندازهی حافظه استاتیک ثابت است و در زمان کامپایل مشخص میشود. حافظهی استاتیک طول عمری برابر با عمر برنامه دارد و مقادیر آن از شروع، تا پایان برنامه، باقی میماند. پاکسازی حافظهی استاتیک به صورت خودکار انجام میشود و با پایان برنامه انجام میشود.
مواردی که در حافظه استاتیک قرار میگیرند :
- Program Binary
- Static variables
- String Literals (in Rust)
Size :
Fixed ( محاسبه در زمان کامپایل )
Lifetime : برابر با طول عمر برنامه
پاکسازی : به صورت خودکار ؛ زمانی که برنامه متوقف میشود .
حافظهی پشته، مسئول نگهداری آرگومانهای تابع و متغیرهای محلی است. پشته، شامل stack frames است که برای هر فراخوانی تابع در زنجیرهای از فراخوانیهای تابع، ایجاد میشوند (به عنوان مثال، A B را فرا میخواند، B C را فرا میخواند). حافظهی پشته به اندازهی مشخصی در زمان کامپایل نیاز دارد؛ به این معنا که آرگومانها و متغیرهای درون stack frames باید اندازههای از پیش تعیین شدهای داشته باشند. اندازهی پشته، پویا است؛ اما دارای حد بالایی ثابتی است که در هنگام راه اندازی برنامه تعریف شدهاست. حافظهی پشته، دارای طول عمری برابر با طول عمر عملکرد است و هنگامیکه عملکرد، نتیجهای را بر میگرداند، پاکسازی آن خودکار است.
بیایید نگاهی به یک مثال ساده در Rust بیندازیم تا حافظهی پشته را بهتر درک کنیم:
fn add(x: i32, y: i32) -> i32 { let sum = x + y; sum } fn main() { let a = 5; let b = 3; let result = add(a, b); println!("The sum is: {}", result); }
هنگامیکه تابع add فراخوانی میشود، یک stack frames دیگر در بالای stack frames main موجود ایجاد میشود. این stack frames جدید حاوی متغیرهای محلی x، y و sum است. مقادیر a و b به عنوان آرگومان به تابع add ارسال میشوند و به ترتیب در x و y ذخیره میشوند. پس از محاسبهی مجموع، تابع add، مقداری را بر میگرداند و stack frames آن به طور خودکار از حافظهی پشته حذف میشود.
سپس تابع main، مقدار برگشتی را از تابع add دریافت میکند و به نتیجهی متغیر اختصاص مییابد. از ماکروی println! برای چاپ نتیجه استفاده میشود. پس از اتمام اجرای برنامه و بازگشت تابع اصلی، stack frames آن نیز از حافظهی پشته حذف میشود و حافظه بهطور خودکار پاک میشود.
در این مثال، میتوانید ببینید که چگونه از stack frames برای ذخیرهی آرگومانهای تابع و متغیرهای محلی در Rust استفاده میشود. اندازهی این متغیرها در زمان کامپایل مشخص میشود و طول عمر حافظهی پشته، برابر با طول عمر تابع است. هنگامیکه تابع برمیگردد، فرآیند پاکسازی آن خودکار است و قاب پشتهی مربوطه را حذف میکند.
Heap Memory
حافظهی Heap، مقادیری را ذخیره میکند که باید فراتر از طول عمر یک تابع مانند مقادیر بزرگ و مقادیر قابل دسترسی توسط رشتههای متعدد، زنده بمانند. از آنجائیکه هر رشته دارای پشتهی مخصوص به خود است، همهی آنها یک پشتهی مشترک دارند. حافظهی Heap میتواند مقادیری با اندازهی ناشناخته را در زمان کامپایل، در خود جای دهد؛ مانند رشتههای ورودی کاربر. اندازهی پشته نیز پویا است؛ با حد بالایی ثابت که در زمان راه اندازی برنامه تعیین میشود. حافظهی Heap طول عمری دارد که توسط برنامه نویس تعیین میشود و برنامه نویس تصمیم میگیرد که چه زمانی باید حافظه تخصیص داده شود. پاکسازی حافظهی هیپ به صورت دستی است و نیاز به مداخلهی برنامه نویس دارد.
در این مثال ساده، روش استفاده از حافظهی پشته نشان داده میشود:
use std::rc::Rc; #[derive(Debug)] struct LargeData { data: Vec<i32>, } impl LargeData { fn new(size: usize) -> LargeData { LargeData { data: vec![0; size], } } } fn main() { let large_data = Rc::new(LargeData::new(1_000_000)); let shared_data1 = Rc::clone(&large_data); let shared_data2 = Rc::clone(&large_data); println!("{:?}", shared_data1); println!("{:?}", shared_data2); }
سپس دو متغیر دیگر را به نامهای shared_data1 و shared_data2 ایجاد میکنیم که با استفاده از Rc::clone، یک شیء LargeData تخصیصیافتهی مشابه را به اشتراک میگذارند. این نشان میدهد که چگونه حافظهی پشته را میتوان در بین متغیرهای متعددی به اشتراک گذاشت؛ حتی فراتر از طول عمر تابع اصلی که داده را ایجاد کرده است.
در این مثال، پاکسازی حافظهی پشته به طور خودکار توسط مکانیزم شمارش مرجع Rust مدیریت میشود (در ادامهی دوره توضیح داده خواهد شد). هنگامیکه تعداد مرجع نشانگر Rc به صفر میرسد (یعنی وقتی همهی متغیرهایی که دادهها را به اشتراک میگذارند از محدوده خارج میشوند)، حافظهی تخصیص داده شده، روی پشته تخصیص داده میشود.
این مثال نشان میدهد که چگونه میتوان از حافظهی پشته برای ذخیرهی ساختارهای داده یا مقادیر بزرگی استفاده کرد که باید بیشتر از طول عمر یک تابع باشند و چگونه میتوان حافظهی پشته را بین چندین متغیر به اشتراک گذاشت.
fn main() { println!("The sum of 2 and 3 is {}", sum(2, 3)); } fn sum(a: i32, b: i32) -> i32 { a + b }
توابع در Rust با استفاده از کلمهی کلیدی fn و به دنبال آن نام تابع، پارامترها و نوع بازگشت (در صورت وجود) اعلام میشوند. در اینجا دستور کلی برای اعلان یک تابع در Rust آمدهاست:
fn function_name(parameter1: type1, parameter2: type2) -> return_type { // بدنه تابع // استفاده از مقادیر یارگشتی در صورت لزوم }
Function Parameters
توابع در Rust میتوانند صفر یا چند پارامتر را داشته باشند. پارامترها در امضای تابع، داخل پرانتز قرار گرفته و با کاما از هم جدا میشوند. در اینجا یک مثال، از یک تابع، با دو پارامتر آورده شدهاست:
fn greet(name: &str, age: i32) { println!("Hello, {}! You are {} years old.", name, age); }
Function Return Values
توابع در Rust میتوانند با استفاده از کلمهی کلیدی return و سپس مقدار بازگشتی، مقداری را برگردانند. یک مثال:
fn square(x: i32) -> i32 { return x * x; }
با این حال، Rust یک سینتکس مختصر را نیز برای برگرداندن مقادیر، از توابع دارد که در آن میتوانید کلمهی کلیدی return را حذف کنید و به سادگی مقداری را که باید در انتهای بدنهی تابع برگردانده شود، مشخص کنید. در اینجا همان مثال، با استفاده از سینتکس کوتاه آمدهاست:
fn square(x: i32) -> i32 { x * x }
Rust همچنین از توابعی با مقادیر بازگشتی چندگانه پشتیبانی میکند که به آنها 'tuples' نیز میگویند. یک مثال:
fn swap(a: i32, b: i32) -> (i32, i32) { (b, a) }
برای استفاده از مقادیر بازگشتی یک تابع tuple، میتوانید tuple را destructure کنید یا از عملگر '.' برای دسترسی به عناصر آن استفاده کنید. در این مثال هر دو روش وجود دارند:
let (b, a) = swap(1, 2); println!("a is {} and b is {}", a, b); let tuple = swap(1, 2); println!("a is {} and b is {}", tuple.1, tuple.0);
struct Point { x: f64, y: f64, }
let point = Point { x: 1.0, y: 2.0 };
let x = point.x; let y = point.y;
let mut point = Point { x: 1.0, y: 2.0 }; point.x = 3.0; point.y = 4.0;
struct Color(u8, u8, u8);
let red = Color(255, 0, 0);
struct Jump; struct Crouch; struct Attack; struct Character { name: String, } fn perform_action(character: &Character, action: &dyn Any) { if action.is::<Jump>() { println!("{} jumps!", character.name); } else if action.is::<Crouch>() { println!("{} crouches!", character.name); } else if action.is::<Attack>() { println!("{} attacks!", character.name); } else { println!("{} does nothing...", character.name); } } fn main() { let character = Character { name: "John Doe".to_string(), }; perform_action(&character, &Jump); perform_action(&character, &Crouch); perform_action(&character, &Attack); }