پرش به محتوای اصلی

راهنمای سبک زنگ زدگی

هکرنیوز۱۴۰۵ مهر ۲۹, چهارشنبه، ساعت ۲۲:۴۱حدود 16 دقیقه مطالعه

آدرس مقاله: https://google.github.io/styleguide/rustguide.html آدرس نظرات: https://news.ycombinator.com/item?id=50186010 امتیاز: 340 # نظرات: 201

این سند یک راهنمای سبک برای استفاده از زبان برنامه نویسی Rust در گوگل است. در این زمینه، "سبک" به چیزی بیش از قالب بندی اشاره دارد. این شامل راهنمایی در مورد API و طراحی پیاده سازی است.

Rust در بسیاری از مکان‌ها از جمله google3، Android، ChromeOS، Fuchsia و Chrome استفاده می‌شود، و ما می‌خواهیم استفاده از Rust در Google هم در داخل و هم در بین پایگاه‌های کد ثابت باشد. راهنمای سبک علاوه بر ایجاد ثبات در کد Rust ما، به ایجاد یک استاندارد کیفیت نیز کمک می کند.

محدوده اختیارات فعلی قوانین ذکر شده در این راهنما:

به طور کلی، ما این سند را به همان دلایلی داریم که یک راهنمای سبک C++ داریم.

اکثر قوانین سبک از یک یا چند مورد از اهداف ذکر شده در زیر می آیند.

ما انتظار داریم که کد ما برای مدت زمان طولانی در دسترس باشد، و اگر قانون سبک خوانایی را بهبود بخشد، کمی تلاش اضافی در طول نوشتن کد در دراز مدت ارزش آن را دارد.

تغییرات در مقیاس بزرگ (LSCs) در Google رایج است و سازگاری به آسان‌تر کردن LSCها کمک می‌کند.

اکوسیستم گسترده‌تر Rust در حال حاضر مقدار بسیار خوبی از ثبات در سبک دارد، و ما باید در صورت امکان به آن تکیه کنیم تا شگفتی را کاهش دهیم و کار را برای یادگیری سبک Rust گوگل کمتر کنیم.

هر توسعه‌دهنده و بازبینی Rust در Google باید این قوانین سبک را در نظر داشته باشد: به این ترتیب، ما باید مراقب باشیم که قوانینی را بگنجانیم که مزایای ملموسی دارند.

موارد زیادی وجود دارد که افراد منطقی ممکن است در مورد یک سبک اختلاف نظر داشته باشند، و ما انتظار داریم که این اختلاف نظر اغلب در CL ها ظاهر شود. داشتن یک قانون سبک کمک می کند تا از تکرار هر بار این موضوع اجتناب کنید. قوانین این دسته که مزایای دیگری ندارند باید به حداقل برسند.

قوانین رسمی سبک Rust را تا حدی دنبال کنید که با این راهنمای سبک در تضاد نباشد.

«تعارض» موردی است که این راهنمای سبک الگویی را پیشنهاد می‌کند که دلسرد می‌شود، یا در تضاد با الگوی تشویقی اولیه در راهنمای سبک Rust است.

چرا راهنمایی در این راهنمای سبک از قوانین معمول سبک Rust منحرف می شود؟

اکثر راهنماهای سبک سه هدف دارند: سازگاری، خوانایی، و تشویق طراحی خوب API. صرف نظر از انتخاب های خاصی که انجام شده است، به همه کمک می کند که این انتخاب ها را از قبل انجام دهند تا دوچرخه سواری را محدود کنند.

این راهنمای سبک این اهداف را به اشتراک می‌گذارد، اما یک هدف اضافی نیز دارد که اغلب دیده نمی‌شود: هموار کردن راه برای تغییرات در مقیاس بزرگ (LSC). پایگاه‌های کد بزرگ مانند بسیاری از مواردی که در Google وجود دارد، گهگاه نیاز به اجرای بازسازگاری‌های مبتنی بر پایگاه کد دارند که با ابزارسازی کمک می‌کنند: برای اینکه این کار به خوبی کار کند، کد باید چیزی باشد که ابزارسازی کار با آن آسان باشد. یکنواختی به این امر کمک می کند، اما داشتن الگوهای عمدی سازگار با فاکتور نیز کمک می کند.

هنگام اعمال قوانین مربوط به طراحی API، باید دو نوع کد را تشخیص دهید:

برای کد کتابخانه، قوانین راهنمای سبک مربوط به طراحی API الزام آور هستند.

برای کد برنامه، قوانین طراحی API یک توصیه قوی است. همانطور که آنها را اعمال می کنید، به خاطر داشته باشید که از آنجایی که کد برنامه برای حل یک مشکل خاص نوشته شده است، به طور کلی باید به سادگی و مستقیم بودن نسبت به قابلیت استفاده مجدد گسترده باشد. از تعمیم و انتزاع زودرس بپرهیزید. بر آنچه برای رفع نیاز فوری لازم است تمرکز کنید.

جعبه یک واحد جمع آوری است. یک جعبه همیشه حاوی یک ماژول Rust بدون نام، "ماژول ریشه" است.

ماژول Rust واحدی از سازماندهی کد درون یک جعبه است. ماژول های Rust برای کنترل دید نام ها استفاده می شوند. ماژول ها می توانند تو در تو باشند. آنها همچنین می توانند برای تقسیم کد بین فایل ها و دایرکتوری ها استفاده شوند.

بخش‌های زیر نشان می‌دهد که در Chromium، ترجیح داده می‌شود از همه امکانات تقسیم ماژول‌ها در بین فایل‌ها استفاده نشود.

جعبه‌های کوچک را در کروم ترجیح دهید. در حالت ایده آل، اما نه لزوما، یک فایل واحد (با تمرکز بر یک انتزاع). اگر کد شما می تواند به جعبه های کوچک تقسیم شود، این کار را انجام دهید.

یک جعبه مربوط به یک قانون rust_static_library (کروم) است که ممکن است حاوی یک یا چند فایل .rs باشد.

ماژول root مجاز است API های عمومی را از زیر ماژول های برگ صادر کند، و زیر ماژول ها را به جزییات پیاده سازی جعبه تبدیل کند (زیرا کاربران نیازی به دانستن این زیر ماژول ها ندارند).

این قانون در مورد جعبه های کوچک به طور یکسان در مورد جعبه های با و بدون زیر ماژول اعمال می شود. ابتدا، ارزیابی کنید که آیا APIها باید در یک جعبه قرار گیرند یا خیر، و تنها پس از آن در نظر بگیرید که آیا زیرماژول ها می توانند به سازماندهی API ها کمک کنند یا خیر.

اگر تصمیم به استفاده از زیر ماژول ها دارید، ساختار فایل مورد انتظار را دنبال کنید.

جعبه‌های بزرگ‌تر زمانی مجاز می‌شوند که قوانین انسجام ضمنی صفت، چندین نوع و ویژگی را مجبور می‌کنند در یک کتابخانه گنجانده شوند، یا اگر در حال ساخت یک کتابخانه بنیادی بزرگ هستید.

به دلیل اندازه انبوه پایگاه کد ما، اثرات غیرمحلی اضافه کردن وابستگی‌ها در نمودار ساخت و بهبود عملکرد کامپایل موازی و ذخیره‌سازی در ساخت، اهداف کتابخانه‌ای ریز در Chromium توصیه می‌شوند.

در Chromium .rs فایل‌های منبع متعلق به یک rust_library (یک جعبه Rust) باید در یک فهرست قرار گیرند.

از دایرکتوری های فرعی برای سازماندهی فایل هایی که متعلق به یک جعبه هستند استفاده نکنید. اگر سازماندهی فایل‌های یک جعبه در زیر شاخه‌ها ضروری به نظر می‌رسد، این نشانه قوی است که جعبه بیش از حد بزرگ شده است و باید تقسیم شود.

این طرح جعبه عمدا با ساختار دایرکتوری Cargo معمولی که معمولا در مخازن منبع باز استفاده می شود متفاوت است.

استثنا: کد زنگ در //third_party که با Cargo نیز ساخته شده است باید از ساختار دایرکتوری Cargo مرسوم پیروی کند.

رویکرد در Chromium توسط عوامل زیر هدایت می شود:

وقتی یک ماژول برگ دارای یک آیتم اصلی تعریف شده توسط کاربر (به عنوان مثال Foo) باشد، ماژول باید به نام آن مورد نامگذاری شود (مانند mod foo و foo.rs).

ماژول های برگ که اساسا در مورد انتزاع خاصی نیستند را می توان به دلخواه نام برد.

این امر شناسایی محتوا/هدف یک فایل منبع یا ماژول برگ را در یک نگاه آسان می کند.

تنها موارد موجود در ماژول‌های بدون برگ باید اعلامیه‌های ماژول (نه تعاریف) و صادرات مجدد باشد.

توجه داشته باشید که تعریف ماژول‌های برگ به ماژول‌های فرعی زیر اجازه می‌دهد: تست mod و ماژول‌های اتصال متقابل زبان مانند #[cxx::bridge].

این کار پیدا کردن چیزها را آسان‌تر می‌کند و از ترکیب ساختار و محتوا جلوگیری می‌کند.

از واردات glob استفاده نکنید، مگر در شرایط زیر که می‌توانید به اختیار خود این کار را انجام دهید:

C++ interop: از آنجایی که فضای نام یکسان (در C++) یک زیرماژول در جعبه‌های Rust مختلف (در Rust) است، می‌توانید با استفاده از واردات glob فضاهای نام را در یک کپی خصوصی ادغام کنید. به عنوان مثال:

در این مثال فرضی، می‌توانید از absl::Status و absl::StrCat از Rust استفاده کنید، همانطور که از C++ استفاده می‌کنید، به‌جای اینکه آنها را به‌عنوان status::absl::Status و رشته‌ها::absl::StrCat بنویسید.

این فقط باید برای ادغام فضاهای نام C++ استفاده شود و ماژول ادغام شده به دست آمده نباید عمومی باشد.

اگر از جعبه‌های شخص ثالثی استفاده می‌کنید که مقدمه را تشویق می‌کنند، این به صلاحدید بازبین است که اجازه دهد.

این نیز به این معنی است که باید از تعریف مقدمات اجتناب شود.

واردات Glob زحمت را برای سرایدارهای کدی که LSCها را اجرا می کنند افزایش می دهد و تشخیص اینکه یک نوع از کجا در زمینه های بدون xrefs آمده است را دشوارتر می کند.

این قانون مطابق با تنظیم rustfmt imports_granularity = Module است.

اساسا نباید هیچ :: در داخل بلوک {..} یک عبارت use وجود داشته باشد. به عنوان مثال:

وارد کردن صفات در بدنه های تابع، مگر اینکه روش های این صفت به طور گسترده در سراسر فایل استفاده شود.

برای استفاده از توابع سطح بالای تعریف شده در ماژول ها یا جعبه های دیگر، ماژول آنها را وارد کرده و با modulename::functionname() فراخوانی کنید. به عنوان مثال:

در Chromium، هنگام وارد کردن توابع از جعبه‌های شخص اول کوچک و تک منظوره.

بسیاری از پایگاه‌های کد Rust به‌طور مداوم سبکی را حفظ می‌کنند که نام‌های کوچک غیرمجاز محلی در نظر گرفته شوند، بنابراین foo() می‌تواند از همان ماژول باشد. این قانون تا حد زیادی برای جلوگیری از اختلاف نظر بینندگان وجود دارد، مزیت آن بیشتر سازگاری و یک مزیت جزئی در خواندن کد بدون xref است.

به طور پیش‌فرض، انواع و ویژگی‌ها باید در کد بدون استفاده از مسیر ماژول‌شان ارجاع داده شوند، به عنوان مثال، کد باید از Regex استفاده کند، نه regex::Regex، با استفاده از regex::Regex در بالای فایل یا به طور بالقوه در تابع مربوطه.

این قانون تا حد زیادی برای جلوگیری از اختلاف نظر بینندگان وجود دارد.

از ابزار قالب‌بندی مناسب (به عنوان مثال، فرمت git cl در Chromium) استفاده کنید.

اگر یک کد بیس به ساختن روی stable اهمیت می دهد و این گزینه در Rust پایدار آنها در دسترس نیست، ممکن است گزینه های rustfmt زیر را اعمال نکند:

حداکثر 100 ستون در هر خط: max_width = 100

استفاده از حروف کوچک در حروف هگزا (0xab123cdef در مقابل 0xAB123CDEF): hex_literal_case = Lower

قالب بندی ماکرو تطبیق دهنده: format_macro_matchers = true

استفاده از Escape برای شخصیت های نامرئی در لفظ. به عنوان مثال، اگر می‌خواهید متنی حاوی یک اتصال دهنده با عرض صفر داشته باشید، از \u{200D} استفاده کنید.

می‌توانید با استفاده از #[rustfmt::skip] از قالب‌بندی خودکار انصراف دهید، اما فقط در شرایط زیر:

مهم: برای انتخاب سبک شخصی، قالب بندی نباید نادیده گرفته شود.

برای مدیریت حافظه، مالکیت منحصر به فرد و قرض گرفتن را به Rc و Arc ترجیح دهید.

به طور کلی، Rust امکان نمایش نمودارهای شی را بدون استفاده از اشاره گرهای هوشمند مالکیت مشترک می دهد. این اشاره گرها سربار زمان اجرا و پیچیدگی منحصر به فرد خود را اضافه می کنند. مهندسانی که از زبان های دیگر می آیند ممکن است تمایل به استفاده از Rc و Arc خیلی سریع داشته باشند.

هنگامی که واقعا به یک کپی عمیق از یک شی نیاز دارید، از .clone() استفاده کنید.

از استفاده از .clone() به عنوان جایگزینی برای استقراض خودداری کنید. کدی طراحی کنید که به طور طبیعی با قوانین مالکیت و قرض Rust کار می کند. با این حال، اگر روابط استقراضی بیش از حد پیچیده شود، .clone() می تواند یک انتخاب عملی باشد.

هنگام انتخاب بین شبیه سازی و قرض گرفتن، نیازهای عملکرد کد را در نظر بگیرید.

توجه: این توصیه برای شبیه‌سازی نشانگرهای Rc یا Arc اعمال نمی‌شود. شبیه‌سازی اشاره‌گرهای شمارش‌شده با مرجع، یک کپی عمیق ایجاد نمی‌کند و راهی مورد انتظار برای استفاده از آنها است.

کپی های عمیق به دلیل تخصیص حافظه و کپی داده ها ممکن است گران باشد.

وقتی توابع داده‌های غیرقابل تغییر و قرضی را می‌پذیرند، از نوع مرجعی استفاده کنید که بیشترین انعطاف‌پذیری را داشته باشد. به جای ارجاع به اشاره گرها، ظروف یا بسته بندی های هوشمند، ارجاعات را به خود داده ها منتقل کنید.

برای زمینه، به Clippy lints borowed_box و ptr_arg مراجعه کنید.

پذیرش انواع مرجع که اشاره گرهای هوشمند، ظروف یا بسته‌بندی‌های خاصی را ذکر نمی‌کنند، عملکردها را متنوع‌تر و کارآمدتر می‌کند: تماس‌گیرندگان می‌توانند داده‌های نگهداری شده را به روش‌های مختلفی بدون کپی کردن ابتدا ارسال کنند.

در صورت امکان تکرار کننده های برگشتی (اعم از انواع بتن یا impl Iterator) را به Vec<T> برگشتی ترجیح دهید.

توجه: در کد برنامه، بازگرداندن یک Vec<T> در صورتی که کد را ساده کند و به انعطاف پذیری و مزایای عملکرد تکرارکننده ها به وضوح نیاز نباشد، خوب است.

معمولا کدهای کتابخانه ای با قابلیت استفاده مجدد زیاد باید در جهت ارائه API های انعطاف پذیرتر و کارآمدتر تلاش کنند. بازگرداندن یک تکرارکننده به تماس‌گیرندگان اجازه می‌دهد تا نحوه مصرف داده‌ها را انتخاب کنند: آن‌ها را در یک بردار جمع‌آوری کنند، آن‌ها را در یک حلقه پردازش کنند، یا آداپتورهای تکرارکننده بیشتری را زنجیره‌ای کنند. برخی از این گزینه ها به کاربران امکان می دهد از تخصیص های غیر ضروری اجتناب کنند.

در کد برنامه، الگوهای استفاده برای یک تابع اغلب آسان‌تر پیش‌بینی می‌شوند. اگر واضح است که عملکرد یک نگرانی نیست، یا به هر حال داده‌ها در یک بردار جمع‌آوری می‌شوند، بازگشت یک بردار باعث ایجاد یک API ساده‌تر می‌شود.

کد کتابخانه بسیار قابل استفاده مجدد باید تکرارگرها را بپذیرد یا اگر فقط نیاز به تکرار روی ورودی دارد، باید IntoIterator را وارد کند.

توجه: در کد برنامه، پذیرش یک قطعه &[T] در صورتی که کد را ساده کند و به انعطاف پذیری و مزایای عملکرد تکرارکننده ها به وضوح نیاز نباشد، خوب است.

معمولا کدهای کتابخانه ای با قابلیت استفاده مجدد بسیار باید سعی در ارائه API های انعطاف پذیرتر و کارآمدتر داشته باشند. توابعی که تکرار کننده ها را می پذیرند به تماس گیرندگان ارائه می کنند:

در کد برنامه، الگوهای استفاده برای یک تابع اغلب آسان‌تر پیش‌بینی می‌شوند. اگر واضح است که عملکرد یک نگرانی نیست، یا تماس گیرندگان همیشه یک بردار دارند، پذیرش یک برش باعث ایجاد یک API ساده‌تر می‌شود.

هنگام طراحی APIهای کتابخانه‌ای که T را می‌پذیرند، اما کاربران احتمالا انواع مختلفی دارند، اگر ارگونومی سایت فراخوانی مهم است، به جای T، به جای T، impl Into<T> را بپذیرید.

نکته: این باید در برابر نگرانی‌های کد نفخ متعادل شود. استفاده از مقدار زیادی از Into<T> در کد شما الزامی نیست.

توجه: کد برنامه تقریبا هرگز نباید از پارامترهای impl Into<T> استفاده کند.

استفاده از impl Into<T> به یک تابع اجازه می دهد تا به طور مستقیم آرگومان های مختلف از انواع مختلف سازگار را بپذیرد. به عنوان مثال، تابعی که impl Into <String> را می پذیرد می تواند مستقیما با یک String یا یک &str واقعی فراخوانی شود.

مبادله در اینجا، ایجاد تعادل بین راحتی اجتناب از .into() در سایت فراخوانی در برابر هزینه های عمومی است (امضای API پیچیده تر، افزایش اندازه کد، گاهی اوقات حتی مشکلات استنتاج نوع).

در مواردی که هدف پارامتر مشخص نیست، به جای bool از پارامترهای تابع enum استفاده کنید.

اگر از bool استفاده می کنید، از یک کامنت درون خطی برای مستند کردن هدف bool در لیست آرگومان استفاده کنید.

مکانیسم گزارش خطا را متناسب با قرارداد API خود انتخاب کنید: گزینه، نتیجه یا وحشت! .

از گزینه برای خرابی های ساده استفاده کنید، جایی که علت واضح است و تماس گیرنده از جزئیات بیشتر بهره نمی برد. این برای نتایج استاندارد و پیش‌بینی‌شده مانند مقدار از دست رفته یا عدم تطابق تجزیه بهترین است.

از Result برای خرابی های قابل بازیابی در جایی که تماس گیرنده برای رسیدگی به خطا به زمینه نیاز دارد استفاده کنید. اینها اغلب خطاهای "غیرقابل اجتناب" ناشی از عوامل خارجی (مانند I/O یا شبکه) هستند که حتی کدهای به درستی پیاده سازی شده نیز نمی توانند با بررسی های پیش از موعد از آنها جلوگیری کنند. با این وجود، تماس گیرنده می تواند به طور منطقی انواع خطاها را پیش بینی کند (یک تابع مرتبط با فایل می تواند با خطای I/O از کار بیفتد). جزئیات خطا به تماس گیرنده اجازه می دهد تا حالت های خرابی را تشخیص دهد و به طور مناسب بازیابی کند.

از وحشت استفاده کنید! برای گزارش اشکالات و ثابت های نقض شده این خطاها قابل اجتناب هستند: برنامه یک بررسی را از دست داده است و بدون انجام یک پیش شرط عملیاتی را فراخوانی می کند. این عیوب باید در کد برطرف شوند، نه در زمان اجرا، اگرچه بازیابی درشت دانه ممکن است با catch_unwind امکان پذیر باشد.

توجه: برخی از پایگاه‌های کد ممکن است به طور کامل از وحشت جلوگیری کنند و حتی نیاز به گزارش‌های ثابت شکسته از طریق Result داشته باشند.

در موارد زیر به جای نام مستعار نوع از newtype استفاده کنید:

انواع با فیلدهای نامگذاری شده را به تاپل ها ترجیح دهید، زیرا نمایه های تاپلی (0.0، 0.1، ...) به سرعت گیج کننده می شوند.

به عنوان یک قاعده کلی، کد کتابخانه سطح پایین باید به طور فعال نیازهای کاربران را پیش‌بینی کند، در حالی که کد برنامه باید در صورت نیاز به ویژگی‌ها اضافه کند.

اگر روشی با هدف و رفتار یک ویژگی کتابخانه استاندارد مطابقت دارد، آن ویژگی را پیاده سازی کنید. به عنوان مثال، به جای نوشتن fn from_str(&str) -> Self on Foo، باید FromStr را برای Foo پیاده کنید.

وجود هر دو روش و صفت به دلایل قابل کشف قابل قبول است.

برای زمینه، Clippy lint should_implement_trait (لیست صفات) را ببینید.

اگر بتوان آنها را به صورت #[derive()] بیان کرد، باید از پیاده سازی های دستی اجتناب شود.

در کتابخانه ها، پذیرش ژنریک (T: Trait یا impl Trait) در پارامترهای تابع را به dyn Trait ترجیح دهید.

برخی از صفات با یکدیگر سازگار نیستند. به عنوان مثال، یک صفت اگر دارای توابع عمومی، توابع مرتبط بدون پارامتر self یا توابعی باشد که Self را برمی گرداند، با dyn سازگار نیست.

یک صفت را فقط برای اهداف زیر تعریف کنید:

برای فعال کردن برنامه‌نویسی عمومی (برای استفاده از T: Trait در محدودیت‌های توابع و انواع عمومی).

برای پذیرفتن یا برگرداندن یک صفت impl یا dyn Trait.

برای تعریف یک صفت بسط (اما اخطارها را در بخش صفات گسترش نیز ببینید).

در تمام موارد دیگری که می‌خواهید عملکردی را برای یک نوع پیاده‌سازی کنید، از یک پیاده‌سازی ذاتی استفاده کنید.

یک صفت توسعه صفتی است که روش‌هایی را به یک نوع از جعبه‌های مختلف اضافه می‌کند.

چیزی که یک صفت بسط را از سایر صفات متمایز می کند این است که تنها هدف آن افزودن روش ها به نوع است. برای استفاده در ژنریک (T: Trait، impl Trait) یا ارسال پویا (dyn Trait) در نظر گرفته نشده است. برای نشان دادن این موضوع، نام یک صفت پسوندی باید دارای پسوند ~Ext باشد (مثلا ForeignTypeExt).

به طور کلی، تیمی که نوع اصلی را در اختیار دارد باید دارای ویژگی پسوند نیز باشد.

توجه: این قانون به طور خاص در مورد صفات پسوندی است. تعریف یک صفت به عنوان یک صفت ورودی (به عنوان مثال، DateLike) و اجرای آن بر روی تعدادی از انواع خارجی نسبتا رایج است.

همچنین می‌توان برای هر نوع که برخی از ویژگی‌های خارجی را پیاده‌سازی می‌کند، یک صفت پسوندی تعریف کرد. در واقع، این معادل افزودن روش های پیش فرض به صفت خارجی است:

وقتی همان تیم مالک صفت پسوند و نوع در حال بسط است، این امر به جلوگیری از تضاد نام روش بین نوع پایه و صفت پسوند یا بین دو ویژگی پسوند کمک می کند.

انواع با فیلدهای عمومی: اجرای صفات را در نظر بگیرید که توسط همه زیرفیلدها اجرا می شوند.

انواع خطا: در صورت امکان، ویژگی Copy را اجرا کنید. مدیریت و انتشار انواع کپی ساده‌تر است، زیرا می‌توان آن‌ها را بدون تغییر مالکیت از طریق ارزش عبور داد. مثالی از مواردی که این امکان وجود ندارد این است که خطا باید حاوی فیلدهای غیر کپی مانند یک رشته باشد.

کپی: هر زمان که به طور منطقی مشخص شد که نوع آن در آینده کپی خواهد بود، اجرا کنید.

Clone: ​​اکثر انواع باید Clone را پیاده سازی کنند مگر اینکه منبع خارجی را نشان دهند.

پیش‌فرض: اگر نوع ()new را پیاده‌سازی کند یا حالت پیش‌فرض داشته باشد، اجرا شود. برای زمینه، Clippy lint new_without_default را ببینید.

PartialEq / Eq: اگر می خواهید کاربران از عملگر == استفاده کنند، اجرای PartialEq را به معادله ترجیح دهید. وقتی معادله را پیاده‌سازی می‌کنید، از بازتابی اضافی مورد نیاز نیز آگاه باشید (جزئیات: https://doc.rust-lang.org/std/cmp/trait.Eq.html).

PartialOrd / Ord: اگر می خواهید کاربران از عملگرهای < یا > استفاده کنند، اجرای PartialOrd را به Ord ترجیح دهید. وقتی Ord را پیاده‌سازی می‌کنید، توجه داشته باشید که نیاز به سفارش کلی دارد (جزئیات: https://doc.rust-lang.org/std/cmp/trait.Ord.html).

اگر یک نوع دارای یک From مهم است که انتظار می رود یکی از راه های اصلی ساخت آن باشد، یک متد ذاتی ::new() ::new_from_foo() ¸ یا ::from_foo() اضافه کنید.

ساختارهایی با فیلدهای کاملا عمومی که عمدتا به عنوان "کیف گزینه" برای یک تابع استفاده می شوند، باید Default را پیاده سازی کنند.

این امکان استفاده راحت از نحو به‌روزرسانی ساختار را فراهم می‌کند (Struct {a: 0, ..Default::default()}).

هرگز به داخل یک mutex مسموم دست نزنید تا به داخل آن نفوذ کنید، مهم نیست که مورد استفاده چقدر وسوسه انگیز به نظر می رسد.

در Chromium، ترجیح دهید از دنباله ها به جای رشته ها استفاده کنید.

به جای یکی از std::sync یا parking_lot از نوع mutex Fuchsia استفاده کنید.

هنگام بررسی نحوه بیان یک API، به ترتیب ترجیح دهید:

توابع، انواع، صفات، اشیاء و ماژول های Rust منظم. (در صورت امکان از ماکروها، تولید کد و فرابرنامه نویسی خودداری کنید).

سایر استراتژی های تولید کد (به عنوان مثال genrule)

هنگامی که تصمیم به استفاده از تولید ماکرو یا کد می‌گیرید، لطفا مزایا را در مقابل هزینه‌های آن بسنجید:

امکانات غیر کلان را ترجیح دهید: ماکروها می‌توانند گویش‌هایی از زبان ایجاد کنند که کار مهندسین را در پایه کد دشوارتر می‌کند. هنگامی که یک خواننده استفاده از یک ماکرو را می بیند، می تواند فرضیات کمتری در مورد آن کد نسبت به زمانی که از یک ماکرو استفاده نکرده باشد، ایجاد کند. نوشتن صحیح ماکروها نسبت به کد معمولی Rust دشوارتر است.

از macro_rules استفاده کنید! برای تولید کد ساده: از آنجایی که ماکروهای Rust بر روی AST کار می کنند، می توانند نسبت به تولید کد متنی شکننده تر باشند.

برای نام‌گذاری روش‌ها از سبک کتابخانه استاندارد Rust پیروی کنید. همچنین به راهنمای نامگذاری قراردادها در دوره جامع زنگار مراجعه کنید.

Lifetime ها باید نام های توصیفی داشته باشند، به خصوص تایپ lifetimes.

از یک نام کوتاه برای پارامترهای عمومی خود (اعم از تک یا چند نویسه)، مربوط به نوع چیزی که آنها را نشان می دهند، استفاده کنید. کلیات تک حرفی اشکالی ندارد، اما حرف انتخاب شده باید تا حدودی نشان دهنده نوع شی باشد، که در حالت ایده آل از مهمترین صفت کران گرفته شده است.

T یا U وقتی که ژنریک ها در یک زمینه نسبتا نامحدود هستند خوب هستند. یعنی یک API است که برای استفاده با اکثر انواع، مانند Vec<T> در نظر گرفته شده است.

هنگام نامگذاری یک صفت پسوندی، نام آن را پسوند ~Ext بگذارید (مثلا ForeignTypeExt).

هنگام نامگذاری توابع اولیه سازی، این دستورالعمل ها را دنبال کنید:

خواندن متن کامل در هکرنیوزبه زبان اصلی، در سایت ناشر باز می‌شود
متن اصلی (انگلیسی)

Rust Style Guide

Article URL: https://google.github.io/styleguide/rustguide.html Comments URL: https://news.ycombinator.com/item?id=50186010 Points: 340 # Comments: 201

همه‌ی اخبار فناوری