Go banner

۱۰ قابلیت دوست‌داشتنی Go

زبان برنامه‌نویسی Go این ماه ۱۰ ساله میشه و در ادامه، ۱۰ تا از قابلیت‌های خوب این زبان دوست‌داشتنی رو می‌خونید.

Map به‌طور پیش‌فرض دارای مقدار صفر است

وقتی از Map استفاده می‌کنیم، حتی اگر یک کلید رو مقداردهی هم نکنیم، می‌توان اون کلید رو دریافت کرد و مقدار اون (به‌جای این‌که nil باشه)، مساوی با «مقدار صفر» (Zero Value) نوع داده اون مپ هستش. مگر این‌که دارای نوع داده «پوینتر» باشه (که در این‌صورت مقدار پیش‌فرض، nil هستش).

بنابراین اگر یک مپ m := map[string]int داشته باشیم، وقتی m["hello"] رو دریافت کنیم، نتیجه برابر با 0 خواهد بود، اگرچه ما کلید hello رو واقعا وارد نکرده باشیم.

در این‌جا 0 مقدار صفر int هستش. اگر مپ ما از نوع string باشه، مقدار کلید مساوی با "" (متن خالی) هستش، یا اگه نوع مپ bool بود، مقدار کلیدها به‌طور پیش‌فرض، مساوی با false خواهد بود.

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

func count(input string) (map[string]int) {
    m := map[string]int{}
    for _,s := range input {
           m[string(s)]++ // always a safe operation
    }
    return m
}

بنابراین نیاز نیست قبل از افزودن شمارنده (در سطر ۴)، بررسی کنیم که کلید string(s) از قبل در مپ موجود هست یا خیر.

مقادیر تغییرناپذیر

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

مقادیر به‌طور پیش‌فرض Nil نیستند

من طرفدار NULL در هیچ زبانی نیستم، بنابراین بسیار خوشحالم که به‌صورت پیش‌فرض، Structها و مقادیر پایه، هیچ‌گاه به Nil اشاره نمی‌کنند، که ما رو از نوشتن بسیاری از دستورات بررسی Nil بودن/نبودن یک مقدار، بی‌نیاز می‌کنه. مگر این‌که از پوینتر استفاده کنید، در این صورت وجود تمامی دستورات بررسی و رسیدگی به خطاها، کاملا ضروری است.

type myStruct struct {} 
func magic(m myStruct) {
     // no pointer, guaranteed that m is not nil
}
func magicp(m *myStruct) {
     // could cause nilpointers!
}

اسلایس Nil و اسلایس خالی یکسان هستند

یک نکته دیگه در مورد Nil این‌که وقتی یک Nil Slice دارید، اساساً تفاوتی با یک slice خالی (غیر Nil) ندارد. بنابراین نیازی نیست که هم Nil بودن و هم خالی بودن یک اسلایس رو بررسی کنید.

func main() {
     var s []int
     if len(s) == 0 {
        fmt.Println("hello")
     }
}

انتشار آسان کتابخانه‌ها

این چیزیه که هیچوقت به‌عنوان یک مسأله مهم بهش فکر نکرده بودم، تا این‌که متوجه شدم انجام این‌کار در Go بی‌اندازه راحت و آسون هستش. من تعدادی کتابخانه Go نوشتم و به‌معنی واقعی کلمه، تنها کاری که باید می‌کردم این بود که کد رو در گیت‌هاب پوش کنم. بعد از اون دیگران می‌تونن با دستور go get github.com/{username}/{lib} کتابخانه من رو دریافت کنند. این روزها کتابخانه‌ها رو به‌صورت Go Module به پروژه اضافه می‌کنید، اما این هم به همون سادگی انتشار در گیت‌هاب هستش.

خودسر است

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

برنامه‌نویسی مولتی پارادایم

بسیاری از کدهای نوشته شده در Go به شی‌ءگرایی گرایش دارند، اما شیء‌گرایی یک ضرورت نیست. در حقیقت زبان Go کاملاً از برنامه‌نویسی فانکشنال (تابعی) پشتیبانی می‌کند.

جامعه برنامه‌نویسان Go

در هر جایی، از IRC و gophers.slack.com گرفته، تا میتینگ‌ها و کنفرانس‌ها، شما می‌توانید افرادی عالی را بیابید که عمیقاً درباره زبان Go اهمیت قائلند. آن‌ها با افراد تازه‌کار برخورد بسیار مناسبی دارند و به کسانی که یادگیری Go را شروع کرده‌اند کمک می‌کنند.

افزون بر این، تشکل‌ها و انجمن‌های بسیار خوب، جامع و متنوعی مانند GoBridge و Women Who Go وجود دارند.

همه‌جا اجرا می‌شود

برنامه‌های نوشته شده با Go تقریباً همه‌جا اجرا می‌شوند. و شما می‌توانید با استفاده از سویچ‌های GOOS، GOARCH، CGO_ENABLED و GOARM آن را برای هر معماری و پلتفرمی کامپایل کنید.

علاوه بر این، Go از اولین زبان‌های برنامه‌نویسی است که قابلیت کامپایل به WebAssembly را به‌طور پیش‌فرض داراست.

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

به‌طور عمدی ساده طراحی شده است

یکی از اهداف اصلی طراحی Go ساده بودن آن بوده است و تا به حال توانسته همین‌طور باقی بماند. شما می‌توانید در مدت زمان نسبتاً کوتاهی مشخصات و جزئیات کامل این زبان را مطالعه کنید. این بدان معنی‌ست که برخی قابلیت‌هایی که در زبان‌های دیگر هست، در Go وجود ندارد. مهم‌ترین آن‌ها Generics است.

سادگی زبان Go بسیار مهم و مفید است. افراد می‌توانند به‌سرعت این زبان را فراگیرند. همچنین احتمال این‌که همکار شما از چیزی استفاده کند که شما تابحال ندیده باشید، بسیار کم است.

به‌علاوه، داشتن مشخصات ساده به این معنی‌ست که پیاده‌سازی کامپایلرهای مختلف برای این زبان راحت‌تر است. مانند TinyGo و GccGo.

این مقاله ترجمه‌ای آزاد از مقاله دیگری به‌همین نام است.

Laravel 6

لاراول ۶ منتشر شد. چه چیزی تغییر کرده است؟

لاراول را می‌توان یکی از شناخته‌شده‌ترین فریمورک‌های PHP دانست. در آخرین نسخه از این فریمورک محبوب (نسخه ۶) چه قابلیت‌هایی اضافه شده است؟

به‌طور کلی در نسخه ۶، بهبودهای نسخه ۵.۸ ادامه پیدا کرده است. پشتیبانی از Laravel Vapor، بهبود پاسخ‌های اعتبارسنجی، Middleware جدید برای Jobها، Lazy Collections، پیشرفت در Sub-Queryها و تفکیک بخش Front-end در یک پکیج جداگانه laravel/ui نمونه‌هایی از این تغییرات است.

تغییر روش شماره‌گذاری نسخه

در گذشته هر شش ماه یک نسخه جدید منتشر می‌شد و زیر عنوان لاراول ۵ منتشر می‌شد. به‌طور مثال ۵.۸. حالا از نسخه ۶ به بعد، لاراول و پکیج‌های رسمی آن، از روش شماره‌گذاری نسخه Semantic Versioning استفاده می‌کند.

در semver هر نسخه شامل سه بخش: اصلی (Major)، فرعی (Minor) و حل اشکال (Patch) می‌باشد. به‌طور مثال در نسخه 6.1.4، نسخه اصلی 6،‌ نسخه فرعی 1 و باگ فیکس 4 هستش.

این بدین معناست که در آینده شماره نسخه‌های لاراول سریع‌تر بالا می‌روند و هر شش ماه نسخه Major بعدی (مثلا نسخه ۷) منتشر می‌شود.

سیاست پشتیبانی

برای نسخه‌های «پشتیبانی طولانی مدت» یا LTS که نسخه ۶ هم یکی از آن‌هاست، ۲ سال پشتیبانی حل اشکال و ۳ سال پشتیبانی امنیتی ارائه می‌شود. این نسخه‌ها بلندترین مدت پشتیبانی و نگهداری را دارند.

برای نسخه‌های عادی، ۶ ماه پشتیبانی حل اشکال و ۱ سال پشتیبانی امنیتی ارائه می‌شود.

برای همه کتابخانه‌ها و پکیج‌های دیگر (مانند Lumen)، تنها آخرین نسخه، پشتیبانی می‌شود.

صفحه خطای استثناء جدید با Ignition

Ignition یک پروژه متن‌باز برای نمایش جزئیات استثناء (Exception) در لاراول است. Ignition قابلیت‌های بهتری نسبت به صفحه خطا در نسخه‌های قبلی لاراول دارد. از جمله آن‌ها می‌توان پشتیبانی بهتر از Blade و گزارش شماره خط کد دارای خطا، راه‌حل‌های قابل اجرا برای خطاهای رایج، ویرایش کد، گزارش وضعیت نشست، کاربر، درخواست و … را نام برد.

صفحه خطای استثناء جدید با Ignition
صفحه خطای استثناء Ignition

بهبود پاسخ‌های اعتبارسنجی

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

در نسخه ۶ لاراول این کار با استفاده از پیام‌های اعتبارسنجی جدید و متد جدید Gate::inspect بسیار ساده‌تر شده است. برای مثال Policy زیر را در نظر بگیرید:

/**
 * Determine if the user can view the given flight.
 *
 * @param  \App\User  $user
 * @param  \App\Flight  $flight
 * @return mixed
 */
public function view(User $user, Flight $flight)
{
    return $this->deny('Explanation of denial.');
}

پاسخ و پیام اعتبارسنجی از این Policy به‌سادگی با استفاده از متد Gate::inspect قابل دریافت است:

$response = Gate::inspect('view', $flight);

if ($response->allowed()) {
    // User is authorized to view the flight...
}

if ($response->denied()) {
    echo $response->message();
}

افزون بر این، با استفاده از Helper متد $this->authorize و یا Gate::authorize در کنترلر یا Route، پیام‌های اعتبارسنجی به‌طور خودکار به Front-End منتقل می‌شوند.

Lazy Collections

بسیاری از برنامه‌نویسان از استفاده از متدهای فعلی Collectionهای لاراول لذت می‌برند. برای تکمیل قابلیت‌های کلاس پرکاربرد Collection، لاراول ۶ کلاس LazyCollection را معرفی کرد که از قابلیت Generatorها در PHP استفاده می‌کند و هم‌زمان که امکان کار با مجموعه داده‌های بسیار حجیم را فراهم می‌کند، مصرف حافظه بسیار کمتری دارد.

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

use App\LogEntry;
use Illuminate\Support\LazyCollection;

LazyCollection::make(function () {
    $handle = fopen('log.txt', 'r');

    while (($line = fgets($handle)) !== false) {
        yield $line;
    }
})
->chunk(4)
->map(function ($lines) {
    return LogEntry::fromLines($lines);
})
->each(function (LogEntry $logEntry) {
    // Process the log entry...
});

یا فرض کنید که می‌خواهید تعداد ۱۰٬۰۰۰ مدل دیتابیس را پردازش کنید، با استفاده از کالکشن‌های عادی لاراول، ابتدا باید تمام ۱۰٬۰۰۰ مدل را یک‌جا در حافظه بارگذاری کنید:

$users = App\User::all()->filter(function ($user) {
    return $user->id > 500;
});

در حالی که در لاراول ۶ متد cursor تنظیم شده است تا یک LazyCollection برگرداند و این اجازه را به شما می‌دهد که کماکان یک‌بار اطلاعات را از دیتابیس دریافت کنید، اما در هر لحظه تنها ۱ مدل در حافظه بارگذاری می‌کند و بنابراین در مصرف حافظه ۱۰٬۰۰۰ برابر صرفه‌جویی می‌شود. در مثال زیر متد filter تنها زمانی اجرا می‌شود که تک‌تک کاربران جداگانه پردازش شده باشند، و به‌مقدار زیادی مصرف حافظه را کاهش می‌دهد:

$users = App\User::cursor()->filter(function ($user) {
    return $user->id > 500;
});

foreach ($users as $user) {
    echo $user->id;
}

بهبود Subqueryهای Eloquent

لاراول ۶ قابلیت‌های مختلفی در پشتیبانی از Sub-Queryهای دیتابیس اضافه کرده است. برای مثال تصور کنید که یک جدول حاوی مقصد پرواز به‌نام destinations و یک جدول پروازها به‌نام flights به مقصدها دارید. جدول flights دارای ستون arrived_at است که نشان‌گر این است که پرواز چه زمانی به مقصد رسیده است.

با استفاده از قابلیت جدید Sub-Query، می‌توان تمام مقصد‌ها (destinations) و نام پروازی که آخرین بار در آن مقصد فرود آمده است را تنها با یک کوئری دیتابیس به‌دست آورد:

return Destination::addSelect(['last_flight' => Flight::select('name')
    ->whereColumn('destination_id', 'destinations.id')
    ->orderBy('arrived_at', 'desc')
    ->limit(1)
])->get();

به‌علاوه، می‌توان از قابلیت Sub-Query جدید برای متد orderBy استفاده کرد تا تمام مقصدها براساس زمانی که آخرین پرواز در آن مقصد نشسته است، مرتب شوند. مجدداً این کار تنها با اجرای یک کوئری دیتابیس قابل انجام است:

return Destination::orderByDesc(
    Flight::select('arrived_at')
        ->whereColumn('destination_id', 'destinations.id')
        ->orderBy('arrived_at', 'desc')
        ->limit(1)
)->get();

پکیج جدید Laravel UI

قابلیت Front-End Scaffolding که پیش‌تر به‌صورت توکار در لاراول (برای کتابخانه Vue) موجود بود، در پکیج laravel/ui استخراج شده است. با این‌کار می‌توان از فریم‌ورک‌های برنامه‌نویسی Front-End دلخواه به‌صورت مجزا استفاده کرده و همچنین نسخه مورد نظر خود را نصب کنید.

بنابراین به‌صورت پیش‌فرض Bootstrap و Vue در لاراول ۶ وجود ندارند. همچنین دستور make:auth مجزا شده است.

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

composer require laravel/ui --dev

php artisan ui vue --auth

[VSCode] معرفی اکستنشن: Auto Rename Tag

[VSCode] معرفی اکستنشن: Auto Rename Tag

Auto Rename Tag یکی از بهترین افزونه‌های ویژوال استودیو کد برای نگارش HTML هست. با این افزونه، وقتی نام یک تگ HTML رو از جایی که تگ باز شده تغییر می‌دید، تگ بسته اون هم تغییر می‌کنه، و بالعکس.

[VSCode] معرفی اکستنشن: Auto Rename Tag

نصب

جهت نصب افزونه کلید نصب را بفشارید. و یا روی این لینک کلیک کنید.

لینک افزونه در VSCode Marketplace
لینک مخزن Git افزونه در گیت‌هاب

تنظیمات

این افزونه به‌طور پیش‌فرض در زبان‌های HTML، XML، PHP و JavaScript فعال هست و برای افزودن زبان‌های دیگه، auto-rename-tag.activationOnLanguage رو به فایل config.json اضافه کنید.
ساختار تنظیمات به این‌صورت هست:

"auto-rename-tag.activationOnLanguage": [
    "html",
    "xml",
    "php",
    "javascript"
]