«ایما» مانکنی است که از اساس ساخته و پرداخته رایانه است. طراحانش موفق شده اند تا کنون ده ها هزار طرفدار برای او پیدا کنند و یک کمپانی ساخت لوازم آرایشی هم برای تبلیغ محصولاتش با او قرارداد بسته است. به نظر شما «ایما» کدام یک از این سه نفر است؟
رباتهای انسان نما (Humanoid robot) به رباتهایی گفته میشود که از لحاظ خصوصیتهای ظاهری بسیار به انسانها شبیه هستند. این گونه رباتها در محیط های انسانی و با ابزار ساخته شده توسط انسان، میتوانند تعامل داشته باشند، برای مثال جسمی را بردارند یا در محیط ِ کار، راه بروند.
در حالت کلی، رباتهای انسان نما از نظر ظاهری شبیه انسان و دارای سر و دو پا و دو دست هستند، در برخی از موارد هم این گونه رباتها علاوه بر موارد فوق دارای صورت، چشم و لب هم میباشند.
دو ربات سورنا ۱ و سورنا ۲ دو نمونه ربات انسان نمای ایرانی هستند که توسط دانشگاه تهران طراحی و ساخته شده اند.
.پاسخ: ایما نفر وسط است.دات کام با عنوان “ هوش مصنوعی انسان نمای سوفیا از نابودی بشر می گوید” ویدیوی ربات انسان نمای سوفیا را تماشا می کنی.
در قسمتهای قبلی فهمیدیم که struct چیست و چه کارهایی میتوان با آن کرد. حالا میخواهیم با هم یک روش دیگر را برای تعریف type های متفاوت در زبان Rust یادبگیریم.
چرا به یک روش دیگر نیاز است و چطوری باید با آن کار کرد؟ برای فهمیدن پاسخ بیایید با هم enum ها را یادبگیریم.
Enum چیست؟
ما با enum، یک type جدید را تعریف میکنیم، امّا با شمردن تمامی حالات ممکن آن. درست همانطوری که از اسم آن، enumeration، به نظر میرسد.
مقادیر یک enum یکسری مقدار ثابت (constant) دارای نام مشخّص اند. برای یک متغیّر از نوع یک enum، در یک زمان مشخّص، تنها یکی از فیلدهای آن معنی دارد. یعنی چی؟ یکم که جلوتر برویم متوجّه میشوید.
شیوهی تعریفکردن enum
برای بیشتر آشنا شدن با جناب enum بهتر است که مثل همیشه سراغ یک مثال برویم.
ما در کامپیوتر رنگها را با فرمتهای مختلفی نمایش میدهیم. یک شکل نمایش به صورت یک عدد هگزادسیمال (hex) است. مثلاً رنگ قرمز خالص را اینطوری نشان میدهند: ff0000.
یک راه دیگر نمایش اعداد در فرمت rgb است. در این فرمت هر عدد را با ۳ عدد طبیعی که بین ۰ تا ۲۵۵ مقدار میگیرند، نمایش میدهیم. مثلاً همان رنگ قرمز این شکلی نمایش داده میشود: (۲۵۵,۰,۰) .
فرضکنید که ما در کدمان فقط همین دو حالت را داریم. پس اگر بخواهیم حالات نوع دادهی Colour را بشماریم، به دو حالت میرسیم: rgb و hex.
گفتیم که موقع تعریف enum یک type جدید را تعریف میکنیم و حالات ممکن آن را میشماریم. پس با این حساب اگر بخواهیم نوع دادهی رنگ را تعریف کنیم، به کدی شبیه به کد زیر میرسیم:
enum Colour {
RGB,
Hex
}
بیایید با بررسی کلمهبهکلمهی این کد بفهمیم که چطوری میتوان یک enum را تعریف کرد.
تعریف یک enumeration با کلمهی کلیدی enum شروع میشود. اینطوری به کامپایلر میفهمانیم که قرار است یک نوعدادهی جدید به شکل enumeration تعریف کنیم.
پس از کلمهی کلیدی enum، اسم type جدیدمان را مینویسم. حالا ما میخواستیم یک type برای رنگ داشته باشیم، به همین خاطر اسمش را گذاشتهایم colour. حواستان باشد که مثل struct ها، اینجا هم اسامی باید PascalCase باشند.
بعد از اسم enum، داخل آکولادها حالتهای مختلف این data type را مشخّص میکنیم. گفتیم که ما فقط ۲ فرمت رنگ را در کدمان داریم، پس اینجا هم فقط اسم همان ۲ نوع را مینویسم و آنها را با کاما (,) از هم جدا میکنیم.
باز هم حواستان باشد که اسم حالاتی که برای یک enum تعریف میکنیم هم باید به شکل PascalCase باشد.
حالا میخواهیم یک متغیّر تعریف کنیم که حالت RGB را نمایش بدهد:
let a = Colour::RGB;
برای این کار ابتدا اسم enum را مینویسیم. اینطوری مشخّص میکنیم که قرار است از چه typeی استفاده کنیم.
بعد از آوردن اسم enum، با عملگر scope resolution (::) مشخّص میکنیم که کدام یک از حالات این نوعداده را میخواهیم. مثلاً اینجا بعد از :: مینویسم: RGB.
مقادیر enum در حافظه چه شکلی ذخیره میشوند؟
در حافظه، مقادیر enum سادهای که ما تعریف کردیم به شکل اعداد صحیح ذخیره میشوند. کامپایلر به ترتیب به هر حالت یک عدد اختصاص میدهد. شروع شمارشش هم از عدد صفر است.
میتوانیم با cast کردن مقدار یک enum بفهمید که عدد پیشفرضی که کامپایلر به آن مقدار اختصاصداده است چقدر است. فقط حواستان باشد که این اعداد قابل تغییر نیستند.
fn main() {
let a = Colour::RGB;
let b = Colour::Hex;
println!("RGB value in memory: {}", a as u8);
println!("Hex value in memory: {}", b as u8);
}
ما در این کد با نوشتن a as u8 مقدار متغیّر a را به نوع u8 تبدیل کردهایم. اینطوری میتوانیم به عددی که کامپایلر برای آن مقدار در نظر گرفته است دسترسی داشته باشیم. خروجی این برنامه این خواهد بود:
RGB value in memory: 0
Hex value in memory: 1
همانطوری که دیدید مقادیر enum به ترتیب شمارهگذاری شده اند.
نکته: کامپایلر همیشه سعی میکند که کوچکترین نوع دادهی عددی را برای ذخیرهی این اعداد استفاده کند تا حداقل فضا را در حافظه اشغال کند.
حالا ممکن است که شما نیازداشتهباشید که این اعداد را خودتان تعیین کنید. چرا؟ چون اینطوری با معنی میشوند. مثلاً یک enum که قرار است status های مختلف یک درخواست http را مشخص کند.
برای این کار ما هنگام تعریف enum، مقدار هر حالت را مشخّص میکنیم:
خب حالا ببینیم که کامپایلر چه مقادیری را برای این حالات درنظر گرفته است:
fn main() {
let a = HttpStatus::Ok;
let b = HttpStatus::NotFound;
let c = HttpStatus::InternalServerError;
println!("Ok value in the memory: {}", a as u8);
println!("NotFound value in the memory: {}", b as u8);
println!("InternalServerError value in the memory: {}", c as u8);
}
با اجرای این برنامه انتظار داریم که اعداد ۲۰۰، ۴۰۴ و ۵۰۰ را ببینیم. درست است؟
Ok value in the memory: 200
NotFound value in the memory: 148
InternalServerError value in the memory: 244
اِ پس چرا اینطوری شد؟ دلیلش همان نکتهای است که بالاتر خواندیم. کامپایلر همیشه کوچکترین data type را برای ذخیرهی این مقادیر درنظر میگیرد. خب کوچکترین نوعدادهی عددی ای که میتواند عدد ۴۰۴ یا ۵۰۰ را ذخیره کند چی است؟ آفرین. u16. امّا ما مقدار را به u8 تغییر دادهایم. اینطوری یک مقدار از داده از دست رفته است و عددی که نمایش داده میشود اشتباه است.
حالا بیایید این بار دو مقدار بعدی را به جای u8 به u16 تبدیل کنیم:
fn main() {
let a = HttpStatus::Ok;
let b = HttpStatus::NotFound;
let c = HttpStatus::InternalServerError;
println!("Ok value in the memory: {}", a as u8);
println!("NotFound value in the memory: {}", b as u16);
println!("InternalServerError value in the memory: {}", c as u16);
}
حالا یک نفس عمیق میکشیم و با استعانت از سیاهچالهی مرکز کهکشان آندرومدا، برنامه را اجرا میکنیم:
Ok value in the memory: 200
NotFound value in the memory: 404
InternalServerError value in the memory: 500
خب حالا همهچیز درست شد و میتوانیم ببینم که کامپایلر آن مقادیری که ما خواسته بودیم را برای هر حالت درنظر گرفته است.
فقط حواستان باشد که در حالت قبلی هم کامپایلر همین مقادیر را برای هر حالت در نظر گرفته بود. ما با کد اشتباهی و تبدیل نادرست مقادیر، عدد اشتباهی را دریافت میکردیم.
استفاده از enum به عنوان مقداری در یک struct
خب حالا ذخیرهکردن نوع رنگ وقتی که خود مقدارش را ذخیرهنکردهایم به چه دردی میخورد؟ حالا چطوری در کنار نوع، مقدار داده را هم ذخیره کنیم؟
برای من و شمایی که تازه struct ها را یادگرفتهایم، پاسخ مشخّص است. کافی است یک struct تعریف کنیم که هم نوع رنگ را ذخیره کند و هم مقدارش را:
همه چیز خوب به نظر میرسد نه؟ ولی خب مسئله این است که rgb سه تا عدد integer است و hex یک String. الان هر دو را مجبوریم به شکل String ذخیره کنیم. ایکاش میشد داده را هم در enum ذخیرهکنیم، نه؟
خب آرزویتان از قبل برآورده شده است. شما در Rust میتوانید داده را هم در enum ذخیرهکنید.
ذخیرهی مقادیر در خود enum
خب حالا میخواهیم که مقادیر را در خود enum ذخیره کنیم. برای حالتی که رنگ به فرمت rgb ذخیرهشده است، میخواهیم ۳ عدد از نوع u16 را نگهداری کنیم تا نشاندهندهی سه مقدار مختلف این فرمت باشد.
برای حالت hex هم میخواهیم که یک String را ذخیره کنیم.
بیایید اوّل کد را با هم ببینیم:
enum Colour {
RGB(u16, u16, u16),
Hex(String)
}
همانطوری که میبینید همهچیز مثل قبل است، با این تفاوت که مقابل نام حالت و داخل پرانتز، دادهای که قرار است درونش ذخیره بشود را مشخّص کرده ایم. مثلاً برای RGB گفتهایم که میخواهیم یک tuple like struct سهتایی را ذخیرهکنیم که ۳ تا عدد از نوع u16 درونش ذخیره میکند.
یا برای Hex گفتهایم که قرار است یک String درونش ذخیره بشود.
حالا درون کد چطوری متغیّری از این نوع و با مقدار مشخّص تعریف کنیم؟
let rgb_colour = Colour::RGB(255, 0, 0);
let hex_colour = Colour::Hex(String::from("ff0000"));
انواع حالات در یک enum
ما در کل ۳ نوع حالت مختلف را میتوانیم در enum ها تعریف کنیم. درست مثل ۳ حالت مختلف structی که داشتیم.
حالت ساده که در بخش ابتدایی دیدیم و همان unit like struct ها اند. حالت دوم که همین بالا دیدیم و مقدار را به صورت یک tuple like struct ذخیره میکنیم.
حالت سوم هم ذخیرهی مقادیر در یک enum به عنوان یک struct معمولی است.
مثلاً در RGB هر عدد نشاندهندهی یک رنگ است. R برای قرمز، G برای سبز و B برای آبی. حالا ما میخواهیم به جای اینکه با یک tuple سهتایی که مقادیرش اسم ندارند، مقادیر را با یک struct مشخّص کنیم.
برای این کار کافی است کد را به شکل زیر تغییر بدهیم:
حالا مقداری که در حالت RGB ذخیره میشود یک struct است. پس ما میتوانیم مقادیر را بدون درنظر گرفتن ترتیبشان و با اسم آنها مشخّص کنیم:
let rgb_colour = Colour::RGB {
blue: 0,
red: 255,
green: 0
};
let hex_colour = Colour::Hex(String::from("ff0000"));
در Rust هرچیزی که برنامهنویسی را سادهتر و کد را خواناتر میکند درنظرگرفتهشده است.
کی باید به جای struct از enum استفاده کرد؟
struct ها ترکیبهایی از نوع «و» منطقی هستند. یعنی تمامی مقادیر باهم یک نوع داده را میسازند. امّا enum ها ترکیبهایی از نوع «یا» منطقی هستند. یعنی یک enum تنها یکی از حالات مختلف است. پس وقتی که یک رنگ از نوع RGB است، اصلاً hex و رفتارهای متناسب با آن برایش تعریف نمیشود.
اگر بخواهیم همین کار را با struct انجام بدهیم، یعنی یک نمونه از struct در یک زمان یا rgb باشد یا hex، باید به سختی و به صورت نصفهنیمه رفتارش را کنترل کنیم تا نتواند در یک زمان هر دو رفتار را داشته باشد.
به علاوه چون کامپایلر میداند که یک نمونه از یک enum نمیتواند همزمان دو حالت را داشته باشد، میتواند فضا را برای ما بهینه کند. مثلاً برای چند حالت تنها یک فضای مشخّص را اختصاص بدهد.
به علاوه از enum ها میتوان در pattern matching هم استفاده کرد. بعداً درموردش خیلی یادمیگیریم.
خب جلسهی آشنایی با enum تمام شد. ما هنوز نمیدانیم که چطوری میتوان به مقادیر ذخیرهشده در یک enum دسترسی داشت. به علاوه enum ها هم مانند struct ها متد و associated function دارند. باید ببینیم که آنها را هم چطوری میتوان تعریف کرد.
برای فهمیدن تمام اینها باید اوّل یک چیز دیگر را یادبگیریم: pattern matching. در جلسهی بعدی به شکل کامل یادمیگیریم که pattern ها چی اند، match چه کار میکند و همهی اینها چطوری زندگی برنامهنویسها را زیبا و بدون باگ میکنند.
با استفاده از سی اس اس میشه از تصاویر و Gradient ها به عنوان بکگراند متن استفاده کرد. در ادامه تصویری که قراره برای بکگراند متن استفاده کنیم رو با همدیگه بررسی می کنیم.
تصویری که قراره برای بکگراند متن ازش استفاده کنیم
قدم اول: یه بکگراند برای تگ
ایجاد کردیم.
قدم دوم: با استفاده از ویژگی background-clip و مقدار text مشخص میکنیم که بکگراند درون متن نمایش داده بشه.
قدم سوم: با استفاده از rgba و مقدار ۰٫۰, ۰, ۰, ۰ رنگ سیاه متن غیر قابل دیدن میشه واینطوری بکگراند دیده میشه.
BACKGROUND
نتیجه کارمون : )
میتونیم از رنگ های دیگه با میزان شفافیت مورد نظر استفاده کنیم و بکگراند های جالبی بسازیم برای مثال:
وقتی که به سرور متصل می شوم یکی از مواردی که من را اذیت می کند نبود ویرایشگرهایی است که به آنها عادت کردم! مثل ویژوال استادیوکد.
نمی خوام دوست داران nano و vim آزده خاطر کنم اما این ویرایشگرها با تمام قابلیت هایشان در برابر ویژوال استادیوکد حرفی برای گفتن ندارند!
حالا فکر کنید می خواهیم از این ویرایشگر قدرتمند در ارتباطات SSH استفاده کنیم!! جذابه مگه نه؟!
اولین کاری که باید بکنید نصب افزونه SSH FS بعد از نصب کافیست از کلید های ترکیبی ctrl + shift +p بگیرید تا کنسول خط فرمان باز شود.
در کنسول خط فرمان بنویسید(چند حرف اول را بنویسید بقیه خطوط را خود به خود به شما نمایش می دهد):
SSH FS: Create a SSH FS configuration
دکمه add بزنید تا به بخش تنظیمات بروید.
بعد با صفحه زیر روبه رومی شوید
حالا کافیست خیلی راحت تنظیمات مربوط به اتصال SSH را در این صفحه انجام بدهید
یکی از ویژگی های خوبی که منم دوست داشتم قابلیت استفاده از پراکسی در این افزونه بود ( نمی دانم عوامل فبلترینگ در حال انجام چه کاری هستند که اکثر پروتکل های امنیتی دچار مشکل شده اند یا موقتی دچار مشکل می شوند به همین دلیل با استفاده از پراکسی می توانید ارتباط راحتر و بدون دردسر تری داشته باشید)
بعد از پرکردن فرم بالا با دستور زیر می توانید به سرورتان وصل بشید.
بعد از اتصال به سرور در سمت چپ میتوانید لیست فایل های موجود در سرور خود را ببنید و آن ها با ویژوال استادیوکد باز کنید و ویرایش کنید.
نکته پایانی
در اتصال به سرور همیشه ما نیاز به ویرایش فایل نداریم گاهی وقت ها نیاز به اجرای یک سری دستورات هم داریم.
در ویژوال استادیو کد با زدن دکمه های ترکیبی ctrl+` به ترمینال دسترسی پیدا کنید و با دستور زیر به سرور خودتان متصل شوید: