<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>پست‌های انتشارات انتشارات GoLang</title>
        <link>https://virgool.io/golangpub/feed</link>
        <description>انتشارات GoLang امیدوار است با تدوین، انتشار و ترجمه مقاله های به روز زبان برنامه نویسی Go Lang قدمی هر چند کوچک در جهت کمک به توسعه دهندگان پارسی زبان بردارد. از همه علاقه مندان دعوت می شود که مقاله های ارزشمند خود را در این انتشارات منتشر کنند.</description>
        <language>fa</language>
        <pubDate>2026-06-16 11:09:03</pubDate>
        <image>
            <url>https://files.virgool.io/upload/publication/nqfxvihdf9rg/e7kof8.png</url>
            <title>انتشارات GoLang</title>
            <link>https://virgool.io/golangpub</link>
        </image>

                    <item>
                <title>آموزش golang - قدم هفتم: عملگرها</title>
                <link>https://virgool.io/golangpub/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-golang-%D9%82%D8%AF%D9%85-%D9%87%D9%81%D8%AA%D9%85-jf9cn4h6fgri</link>
                <description>سلام دوستانتو این قسمت درمورد عملگرها تو go توضیح میدم. زبان گو هم مثل سایر زبان ها دارای یکسری عملگرها مانند: عملگرهای حسابی, عملگرهای مقایسه ای, عملگرهای منطقی و عملگرهای بیتی هست.عملگرهای حسابی:زبان گو ۵ تا عملگر حسابی داره:جمع (+)تفریق‌(-)ضرب‌(*)تقسیم (/)باقیمانده (٪)a := 1 
b := 2 
c := a + b 
// 3 
d := a - b 
// -1 
e := a * b 
// 2 
f := a / b 
// 0 
g := a % b 
// 1عملگرهای مقایسه ای:زبان گو ۶ تا عملگر مقایسه ای داره:مساوی بودن با (==)مساوی نبودن با (=!)کمتر از (&gt;)کمتر یا مساوی با (=&gt;)بزرگتر (&lt;)بزرگتر یا مساوی با (=&lt;)حاصل استفاده از این عملگرها مقدار true یا false می باشد.a := 1
 b := 2
 c := 1

a == b   // false
a &lt; b   // true
a &lt;= c   // true
c != a   // false
c != b   // trueعملگرهای منطقی:زبان گو ۳ تا عملگر منطقی داره:AND ( &amp;&amp; )OR ( || )NOT ( ! )عملگر &amp;&amp; به انگلیسی AND به فارسی &quot;و&quot;: اگر هردو عملگر true باشه مقدار بازگشتی true و در غیر اینصورت false میشه.عملگر || به انگلیسی OR به فارسی یا , اگر یکی از عملگرها true باشه مقدار بازگشتی true در غیر این صورت false میشه.عملگر ! به انگلیسی NOT به فارسی نفی: زمانیکه شما از عملگر ! استفاده می کنید معکوس نتیجه عملوند را نیاز دارید.a := true  b := true  c := false   fmt.Println(a &amp;&amp; b) //true  fmt.Println(a || b) //true  fmt.Println(!a)     //false  fmt.Println(!c)     //trueعملگرهای بیتی:زبان گو ۵ تا عملگر بیتی داره:شیفت بیتی به چپ (&gt;&gt;)شیفت بیتی به راست (&lt;&lt;)AND ( &amp; )OR ( | )XOR ( ^ )عملگر &gt;&gt; به انگلیسی Zero fill left shift یا به اختصار left shift به فارسی شیفت بیتی به چپ، مقدار باینری ما را با استفاده از انتقال یا اضافه کردن صفر ها به سمت چپ انتقال میده.عملگر &lt;&lt; به انگلیسی Zero fill right shift یا به اختصار right shift به فارسی شیفت بیتی به راست، مقدار باینری ما را با به سمت راست انتقال میده.اولویت عملگرهادر زبان گو ما یکسری اولویت ها برای عملگرها داریم و همچنین در زبان گو مثل سایر زبان ها عبارات داخل پرانتز () نسبت به سایر عبارات اولویت دارن. برای درک بهتر عملکرد عملگرها لازمه اولویت اون ها رو بشناسیم. (به ترتیب از بالا به پایین اولویت بیشتر دارن)*   /   %   &lt;&lt;  &gt;&gt;  &amp;   ^&amp;  +   -   |   ^  ==  !=  &lt;   &lt;=  &gt;   &gt;=  &amp;&amp;  ||
 https://virgool.io/@saeedheydari/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D9%85%D9%82%D8%AF%D9%85%D8%A7%D8%AA%DB%8C-golang-%D9%82%D8%AF%D9%85-%D8%B5%D9%81%D8%B1-ufv22zb4j3bq  https://virgool.io/@saeedheydari/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D9%85%D9%82%D8%AF%D9%85%D8%A7%D8%AA%DB%8C-golang-%D8%A8%D8%AE%D8%B4-%D8%AF%D9%88%D9%85-wyvs1idjyan2  https://virgool.io/@saeedheydari/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-golang-%D9%82%D8%AF%D9%85-%D8%B3%D9%88%D9%85-e3mxmjr1mp74  https://virgool.io/@saeedheydari/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-golang-%D9%82%D8%AF%D9%85-%DA%86%D9%87%D8%A7%D8%B1%D9%85-ydltpxgtgdlj  https://virgool.io/@saeedheydari/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-golang-%D9%82%D8%AF%D9%85-%D9%BE%D9%86%D8%AC%D9%85-regehw9odr8y  https://virgool.io/@saeedheydari/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-golang-%D9%82%D8%AF%D9%85-%D8%B4%D8%B4%D9%85-k6cpaqgybxz2  https://virgool.io/@saeedheydari/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-golang-%D9%82%D8%AF%D9%85-%D9%87%D9%81%D8%AA%D9%85-%D9%85%D8%AA%D8%BA%DB%8C%D8%B1%D9%87%D8%A7-%D9%88-constant-oqvlbp5q2hg6  https://virgool.io/@saeedheydari/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-golang-%D9%82%D8%AF%D9%85-%D9%86%D9%87%D9%85-%D8%AA%D8%A7%D8%A8%D8%B9-nat6a2yfyqe3 </description>
                <category>انتشارات GoLang</category>
                <author>سعید حیدری</author>
                <pubDate>Tue, 10 Jan 2023 00:11:49 +0330</pubDate>
            </item>
                    <item>
                <title>الگوهای طراحی در زبان گو (Design patterns in go)-مقدمه</title>
                <link>https://virgool.io/golangpub/design-patterns-in-go-intro-rab9ekreapzm</link>
                <description>فهرستسلام به همه دوستانعلی فرهادنیا هستم و این بار اومدم با یه موضوع جذاب.الگوهای طراحی اونم در زبان گولنگکلا این الگوهای طراحی مبحث جالبیه و پایه ثابت خیلی از مصاحبه ها هم هست و بلد بودنشون خیلی خوبه.همونطور که در سری مقله های اصول سالید در گولنگ ( که هنوز کامل نشده)  اشاره کردم زبان گولنگ شی گرا نیست و خب این الگوهای طراحی اکثرا بر اساس منطق شی گرا ایجاد شدن.پس تکلیف چیه؟ خب مثل همون اصول سالید میشه اینجاهم کارایی کرد و یه جورایی این الگوهارو گولنگیزشون کرد.در این سری از مقاله ها سعی میکنم این اصولو با زبان گولنگ پیاده سازی کنم و توضیح بدم.ساختار کلیالگوهای طراحی بر اساس عملکردشون به سه دسته تقسیم میشن:الگوهای طراحی سازنده (Creational Design Patterns) این الگوها روشهای مختلف ایجاد یک شی رو ارائه میدن و باعث افزایش انعطاف پذیری و توانایی استفاده مجدد از کد میشن.الگوهای طراحی ساختاری (Structural Design Patterns)مجموعه ای از راه حل هایی هستن که برای حل یه سری مشکلات توی زمینه توسعه پذیری نرم افزار راه حل هایی ارائه میدن.الگوهای طراحی رفتاری (Behavioral Design Patterns)این الگو ها مجموعه ای از راه حل ها برای ارتباط بین اشیا مختلف هستند.من سعی میکنم این الگوهارو طبق همین دسته بندی ارائه بدم.منابعمنابع اصلیم شامل یه دوره ویدئویی میشه که این لینکشه  و منبع دیگم این وبسایته.کدهایی که توی این سری از مقالات مینویسمو میتونید توی این ریپازیتوری گیتهام پیدا کنید.فهرست</description>
                <category>انتشارات GoLang</category>
                <author>علی فرهادنیا</author>
                <pubDate>Fri, 18 Feb 2022 01:00:37 +0330</pubDate>
            </item>
                    <item>
                <title>برسی الگوریتم رمزنگاری rabbit و پکیج rabbitio در گولنگ</title>
                <link>https://virgool.io/golangpub/%D8%A8%D8%B1%D8%B3%DB%8C-%D8%A7%D9%84%DA%AF%D9%88%D8%B1%DB%8C%D8%AA%D9%85-%D8%B1%D9%85%D8%B2%D9%86%DA%AF%D8%A7%D8%B1%DB%8C-rabbit-%D9%88-%D9%BE%DA%A9%DB%8C%D8%AC-rabbitio-%D8%AF%D8%B1-%DA%AF%D9%88%D9%84%D9%86%DA%AF-tg4gr75249bk</link>
                <description>این مطلب از وبلاگ توسعه دهندگان SNIX کپی برداری شده است... لینک پست درblog.snix.irتوی این دوره زمونه رمزنگاری اطلاعات یکی از مهم ترین بخش های دنیای دیجیتال هست، البته اهمیت رمزنگاری اطلاعات و استفاده از اون حتی به قبل از دنیای دیجیتال برمیگرده، شاید این جمله رو شنیده باشید که میگه information is power .. قطعا ارزش اطلاعات در هر برهه ای از تاریخ حائز اهمیت بوده، از زمان امپراطوری روم تا جنگ جهانی اول و انیگما در جنگ جهانی دوم و دوران جنگ سرد میتونیم اهمیت رمزنگاری اطلاعات و نقش اون توی تغییر سرنوشت بشریت رو مشاهده کنیم.قطعا رمزنگاری توی دنیای دیجیتال و خصوصا با گسترش اینترنت نقش خیلی پررنگ تری نسبت به قبل ایفا میکنه. برای مثال حتی همین پستی که شما دارید میخونید رمز شده.ولی رمزنگاری چیه؟ رمزنگاری در دنیای دیجیتال به معنی ناخوانا کردن اطلاعات برای افراد ثانویه با استفاده از الگوریتم های ریاضی هست. به صورتی که فرستنده و گیرنده بتونن این اطلاعات رو با یک یا چند کلید رمز و رمزگشایی کنن.تا به امروز قالب بر چند صد الگوریتم مختلف رمزنگاری منتشر شده که هرکدوم مزیت ها، مشکلات و نقص های امنیتی خودشونو دارن. توی این پست میخوایم الگوریتم رمزنگاری rabbit یا خرگوش رو مورد بررسی قرار بدیم.. به صورت خلاصه نحوه رمزنگاری اطلاعات توی این الگوریتم رو مرور کنیم و با یکی از الگوریتم های دیگه از نظر امنیت مقایسش کنیم و در نهایت پرفورمنس rabbit رو اندازه گیری کنیم.الگوریتم rabbit یا rabbit cipher (به الگوریتم رمزنگاری cipher میگن) در سال 2003 ارائه و در سال 2008 برای استفاده عموم منتشر شد. این الگوریتم که از نوع stream cipher و symmetric هست از اولش برای افزایش امنیت اطلاعات ارائه شد اما بعدا مشخص شد که علاوه بر امنیت، سرعت بسیار بالایی هم داره. قبل از اینکه ادامه بدیم:منظور از stream cipher چیه: همونطور که از اسمش پیداست به این معنیه که اطلاعات بایت به بایت رمز میشن.. برخلاف block cipher که یک بلوک از اطلاعات رو (مثلا 64 بیت) رمز میکنهمنظور از symmetric چیه: الگوریتم های رمزنگاری از نظر نوع کلید به دو دسته symmetric و asymmetric دسته بندی میشن. symmetric ها برای رمزگذاری و رمزگشایی از یک کلید استفاده میکنن مثله rabbit و asymmetric ها برای رمزگشایی از private key و برای رمزگذاری از public key استفاده میکنن مثله RSAمفهوم plain-text: اطلاعاتی که رمز نشده هستند و برای همه قابل خواندن هستمفهوم cipher-text: اطلاعاتی که توسط یک cipher رمز شده و برای همه قابل خواندن نیستمزیت رمزنگاری symmetric:بسیار سریع هستنبسیار امن هستن ( شکستن دیتا با استفاده از حمله Brute-force مدت زمان زیادی طول میکشه)طول cipher-text مساوی یا کمتر از plain-text هستمزیت رمزنگاری asymmetric:کلید خصوصی به اشتراک گذاشته نمیشهفرستنده و گیرنده و پیام تایید هویت میشهدر پروتکل TLS از هردو روش استفاده میشه... برای تایید هویت از RSA یا DSA و برای رمزنگاری از AES یا DES و جدیدا با chacha20نحوه رمزنگاری اطلاعات در الگوریتم rabbit: این الگوریتم برای رمزنگاری از یک کلید 16 بایتی و Initialization vector هشت بایتی استفاده میکنه. Initialization vector اختیاری هست. توی ورژن های اولیه Initialization vector وجود نداشت و به منظور امنیت بیشتر اضافه شد.این Initialization vector چیه: بعضیا بهش تاس هم میگن.. معمولا یک مقدار تصادفی هست که به منظور افزایش امنیت ازش استفاده میشه، به طور خلاصه کاری که انجام میده اینکه که اطمینان حاصل میکنه که cipher-text های تولید شده از یک plain-text شبیه به هم نباشن... مثال: فرض کنید hello-world رو با کلید secret-key رمز کردید.. اگه لازم باشه اینو چند بار روی یک کانکشن ارسال کنید، حمله کننده مرد میانی (شنود کننده اطلاعات یا فرد ثانویه) از متن پیام که hello-world هست با خبر نمیشه اما قطعا میفهمه که شما دارید یک plain-text ثابت رو چند بار ارسال میکنید. نقش iv اینجا مطرح میشه.. با استفاده از iv هر cipher-text تولید شده از یک plain-text ثابت با استفاده از کلید با مقدار قبلیش فرق میکنه. اگه از iv استفاده کنید باید با هر cipher-text این iv هم ارسال بشه.. البته ارسال این iv و مطلع شدن فرد ثانویه از این iv ها هیچ خطری نداره.امنیت اطلاعات در rabbit: از اونجایی که rabbit از کلید 128 بیت استفاده میکنه شکستن اطلاعات به روش brute-force مدت زمان غیر قابل تصوری طول میکشه.. برای مثال کل شبکه بیت کوین رو درنظر بگیرید، شکستن کلید rabbit برای این شبکه 70,000,000,000,000,000,000,000,000 سال طول خواهد کشید. حتی برای تکنولوژی های جدید اینده مثل کامپیوتر های کوانتومی هم شکستن این کلید به مدت زمان 12^10*2.61 سال طول میکشه ... برای اینکه بزرگی این مدت زمان ها دستتون بیاد لازمه بدونید کل سن جهان هستی از زمان بیگ بنگ تا الان تقریبا 10^10*1.38 تخمین زده شده...نحوه رمزنگاری اطلاعات: اندازه internal state این سایفر 513 بیت هست که شامل 8 متغیر 4 بایتی state و 8 متغیر 4 بایتی counter و یک بیت به عنوان carry میشه.تابع setup key: این تابع کلید 16 بایتی رو به 8 ارایه 2 بایتی تبدیل میکنه و با این ارایه ها متغیر های state و counter محاسبه میشن.به منظور کاهش ارتباط بین کلید و متغیر های internal state فانکشن next state چهاربار اجرا میشه..تابع setup iv: این تابع مقدار iv رو که 8 بایت هست با متغیر های counter که 8 بایت هستند xor میکنهبعد از این 4 بار دیگه فانکشن next state اجرا میشه تا متغیر های counter جدید با state ها محاسبه مجدد بشن.در فانکشن next state متغیر های counter هر بار با بیت carry و ثابت های rabbit (هشت ثابت چهار بایتی) sub32 میشن.. تابع sub32 برای محاسبه difference پارامتر اول، دوم و سوم استفاده میشه. توی این حالت پارامتر اول فیلد ارایه ثابت هاست و پارامتر دوم فیلد متناظر ارایه counter ها و پارامتر اخر هم carry هست..تابع extract: توی این تابع حالت های مختلف متغیرهای state با همدیگه xor میشن.. که در نهایت باعث تولید key stream میشه..رمزگذاری و رمزگشایی: هر بایت از key stream که اسلایسی به طول 16 هست با هر بایت از plain-text یا همون دیتای رمز نشده xor میشه و اون بایت از key stream حذف میشه... در نهایت وقتی طول key stream به صفر رسید دوباره extract انجام میشهبرای اطلاعات بیشتر میتونید به RFC 4503 و پروپوزال رسمی ارائه شده مراجعه کنید.پروژه eSTREAM و rabbit: پروژه eSTREAM که توسط EU ECRYPT (سازمان تحقیقاتی امنیت اطلاعات و رمزنگاری اتحادیه اروپا) حفظ میشه هدفش پیدا کردن و ارائه دادن cipher stream های بهینه و امن برای استفاده عمومی و گسترده هست. rabbit فاز سوم این پروژه رو پشت سر گذاشته و به همراه HC-128 و Salsa20/12 و SOSEMANUK به عنوان کاندید های نرم افزار مورد تایید قرار گرفته.‌‌‌‌ ‌‌‌‌‌‌مقایسه rabbit با الگوریتم های ضعیف تر، encrypt تصویر... : برای مقاسه من سایفر AES-ECB رو انتخاب کردم. و میخوام باهاش یک تصویر رو encrypt و نمایش بدم...چون میخوام تصویر رمز شده رو نمایش بدم پس نباید header های فایل رو رمز کنم... اگه کل فایل png رو رمز کنم header ها هم رمز میشن و فایل دیگه با اپلیکیشن های مشاهده تصویر باز نمیشه.. چون هدر ها هم تغییر کردن.. برای مشاهده تصویر رمز شده باید فقط اطلاعات مربوط به نحوه رنگ دهی پیکسل ها encrypt بشه.. البته png سختار پیچیده ای داره و من برای سادگی کار تصویر png رو به فورمت ppm که نسبتا ساده تر هست تبدیل میکنم...فرمت تصویر ppm: این فرمت شامل هدر و به دنبال اون دیتا میشه .. توی ورژن P3 هدر به صورت P3 1024 788 255 تعریف میشه و از لاین بعد کد رنگ هر پیکسل به صورت ascii تعریف میشه.. مثلا اگه این کد رو توی فایل text کپی کنید و با پسوند ppm ذخیره کنید، تصویر 3 در 4 پیکسل رو میتونید ببینید.P3 3 4 255 
255 0 0 0 255 0 0 0 255 255 255 0 255 255 255 0 0 0 0 255 255 75 75 75 127 127 127 150 150 150 150 150 150 150 150 150توی ورژن P6 این فرمت فایل اطلاعات به صورت باینری توی فایل ذخیره میشن.. که کار رو برای encrypt کردن دیتا راحت تر میکنه.. پس فایل png رو تبدیل به ppm P6 میکنم.خب من با دستور convert از پکیج imagemagick عکس png رو تبدیل به ppm میکنم:# apt install imagemagick
# convert logo.png logo.ppmواسه اینکه بفهمم طول هدر چند بایت هست این فایل logo.ppm رو با دستور xdd یا hexdump برسی میکنم..# hexdump -C logo.ppm | head -n 3
00000000  50 36 0a 33 38 34 20 33  38 34 0a 32 35 35 0a 00  |P6.384 384.255..|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|پس طول هدر این عکس 15 بایت هست و باید این 15 بایت رو از فایل جدا کنم و فایل رو با الگوریتم رمز کنم و دوباره هدر رو به اطلاعات رمز شده اضافه کنم..عکسی که انتخاب کردم اینه ... ‌‌تصویر اورجینال‌خب برای رمزنگاری این فایل با سایفر AES-ECB میخوام از openssl استفاده کنم و برای رمزنگاری با rabbit از کتابخونه snix.ir/rabbitio و زبان go استفاده میکنم.. این پکیج رو میتونید از git.snix.ir یا میرور گیت هاب دریافت کنیدبرای جدا کردن 15 بایت اول فایل logo.ppm توی لینوکس از دستور dd کمک میگیرم:# dd if=logo.ppm bs=1 count=15 of=header.bin
15+0 records in
15+0 records out
15 bytes copied, 0.000500669 s, 30.0 kB/sهدر رو توی فایلی به اسم header.bin ذخیره کردم... اما فایل logo.ppm هنوز header رو داره .. پس باید هدرش رو پاک کنیم که فقط اطلاعات رنگ بندی RGB باقی بمونه ... بعد از اینکار این فایل دیگه نباید با نرم افزار های نمایش عکس باز بشه...# dd if=logo.ppm bs=1 skip=15 of=temp-logo &amp;&amp; mv temp-logo logo.ppm
442368+0 records in
442368+0 records out
442368 bytes (442 kB, 432 KiB) copied, 1.22259 s, 362 kB/sو در نهایت با دستور openssl فایل logo.ppm رو رمز میکنیم.. یادمون باشه که فایل logo.ppm الان فقط شامل دیتای RGB هست..# cat logo.ppm | openssl enc -aes-128-ecb -K 6162636465666768696a6b6c6d6e6f70 -nosalt -out enc-rgb.data
# cat enc-rgb.data &gt;&gt; header.bin
# mv header.bin aes-ecb-logo.ppmتوی دستورات بالا دیتای RGB رو رمز کردیم و cipher-text به دست اومده رو به header.bin اضافه کردیم... و نام header.bin رو به aes-ecb-logo.ppm تغییر دادیم..تصویری که به دست اومد به این شکله... ‌‌تصویر encrypt شده با AES-128-ECB‌‌‌ و این عکس الان مصداق بارز الگوریتم رمزنگاری ضعیف هست... مفهوم تصویر کاملا مشخصه فقط شاید از لحاظ جزئیات یکم تغییر کرده باشه...حالا عکس اورجینال رو با استفاده از rabbit و با زبان گولنگ encrypt میکنیم.. تا ببینیم چه تفاوتی داره..package main
import (
	&amp;quotio&amp;quot
	&amp;quotos&amp;quot
	&amp;quotlog&amp;quot
	
	&amp;quotsnix.ir/rabbitio&amp;quot
)

const (
	headerLen = 15
)

var (
	key = []byte(&amp;quotabcd1234abcd1234&amp;quot) // key 16 byte
	ivx = []byte(&amp;quotrandom-x&amp;quot) // iv 8 byte
)

func main() {
	log.SetFlags(0) // just logs, no time and date... 

	// open logo-orginal.ppm file... 
	org, err := os.Open(&amp;quotlogo-orginal.ppm&amp;quot)
	if err != nil {
		log.Fatal(err)
	}
	
	
	// create a file to write cipher-text in it.
	enc, err := os.Create(&amp;quotlogo-rabbit.ppm&amp;quot)
	if err != nil {
		log.Fatal(err)
	}
	
	// write header to logo-rabbit.ppm without encryption...
	hnn, err := io.CopyN(enc, org, headerLen)
	if err != nil {
		log.Fatal(err)
	}
	
	log.Printf(&amp;quotppm header to file: %d byte copied&amp;quot, hnn)
	
	// new rabbit writer cipher .. 
	stream, err := rabbitio.NewWriterCipher(key, ivx, enc)
	if err != nil {
		log.Fatal(err)
	}
	
	// copy data through rabbit cipher.. 
	if _, err := io.Copy(stream, org); err != nil {
		log.Fatal(err)
	}
	
	log.Printf(&amp;quotdone *** &amp;quot)
}با استفاده از کامپایلر go کد زیر رو کامپایل و اجرا میکنیم...# nano main.go
# go mod init rabpic &amp;&amp; go mod tidy
# go build -o rabbit
# ./rabbit
ppm header to file: 15 byte copied
done ***و در نهایت تصویر به دست اومده به این شکل هست.. ‌ ‌‌تصویر encrypt شده با  Rabbit-128‌‌ ‌‌‌‌خب هیچ چیزی از تصویر اصلی مشخص نیست.. و تصویر کاملا encrypt شده.. برای decrypt کردن کافیه برنامه رو یکبار دیگه اجرا کنید.. البته برای عکس ورودی باید همین تصویری که رمز شده رو بدید ... اگه اینکارو انجام بدید خروجی برنامه تصویر اصلی میشه ...بررسی پرفورمنس rabbit: قبل از هر چیز پروژه eSTREAM یک بنچمارکی تهیه کرده که توش بیشتر cipher ها رو از نظر پرفورمنس با هم مقایسه کرده.. بنچمارک پردازنده pentium mاگه به لیست دقت کنید متوجه میشید که rabbit بین 10 الگوریتم برتر هست.. البته بیشتر این الگوریتم ها به دلیل اسیب پذیری هایی که داشتن نتونستن فاز های مربوطه eSTREAM رو با موفقیت بگذرونن و شکست خوردن. توی این لیست فقط HC-128 و HC-256 موقعیت برتری نسبت به rabbit دارن. البته الگوریتم های HC-128 و HC-256 یک مشکل پرفورمنسی دارن.. شاید از نظر stream کردن یه مقدار از rabbit سریع تر باشن اما فانکشن های setup iv این الگوریتم ها به شدت کُند هست.. پس برای رمزنگاری cipher-text های کوتاه اصلا مناسب نیستن..تا حالا که تا اینجای کار اومدیم بریم برای تست benchmark این cipher در گولنگ ... کد تست مربوطه به این صورت نوشته شده.. برای اینکه بتونیم مقدار زمان و منابعی که برای این الگوریتم صرف میشه رو محاسبه کنیم من دوتا تست اوکی میکنم، یک تست که فقط یک مقدار معینی از داده رو از یک بافر به بافر دیگه کپی میکنه و یک تست دیگه که علاوه بر کپی دیتا رو با rabbit cipher رمز هم میکنه.. در نهایت میتونیم با کم کردن زمان و منابع تست کُپی از تست rabbit مقدار تقریبی زمان و منابع رو مشخص کنیم..package rabbit_test

import (
	&amp;quotbytes&amp;quot
	&amp;quotio&amp;quot
	&amp;quotmath/rand&amp;quot
	&amp;quotstrings&amp;quot
	&amp;quottesting&amp;quot

	&amp;quotsnix.ir/rabbitio&amp;quot
)

const dataLEN = 2 &lt;&lt; 10 // 2 KB

var TEXT = makeRandomText(dataLEN)

func makeRandomText(n int) string {
	b := make([]byte, n)
	chr := []byte(&amp;quotJDDYDG&amp;quot)
	for i := range b {
		b[i] = chr[rand.Intn(len(chr))]
	}
	return string(b)
}

func BenchmarkRabbit(b *testing.B) {
	key := []byte(&amp;quotabcd1234abcd1234&amp;quot) // key 16 byte
	ivx := []byte(&amp;quotrandom-x&amp;quot)         // iv 8 byte
	msg := strings.NewReader(TEXT)
	bf := new(bytes.Buffer)
	cph, _ := rabbitio.NewWriterCipher(key, ivx, bf)
	if _, err := io.Copy(cph, msg); err != nil {
		b.Fatal(err)
	}
}

func BenchmarkCopy(b *testing.B) {
	msg := strings.NewReader(TEXT)
	bf := new(bytes.Buffer)
	_, err := io.Copy(bf, msg)
	if err != nil {
		b.Fatal(err)
	}
}و این نتیجه تست روی سیستم من هست.. توی کد بالا 2 کیلوبایت رشته رو کپی و رمز کردیم... نتایج تست روی سیستم های مختلف ممکنه متفاوت باشه# go test -v -bench=. -benchmem -count 4
goos: linux
goarch: amd64
pkg: rabpic
cpu: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
BenchmarkRabbit
BenchmarkRabbit-8       1000000000               0.0000122 ns/op               0 B/op          0 allocs/op
BenchmarkRabbit-8       1000000000               0.0000140 ns/op               0 B/op          0 allocs/op
BenchmarkRabbit-8       1000000000               0.0000124 ns/op               0 B/op          0 allocs/op
BenchmarkRabbit-8       1000000000               0.0000141 ns/op               0 B/op          0 allocs/op
BenchmarkCopy
BenchmarkCopy-8         1000000000               0.0000021 ns/op               0 B/op          0 allocs/op
BenchmarkCopy-8         1000000000               0.0000026 ns/op               0 B/op          0 allocs/op
BenchmarkCopy-8         1000000000               0.0000019 ns/op               0 B/op          0 allocs/op
BenchmarkCopy-8         1000000000               0.0000027 ns/op               0 B/op          0 allocs/op
PASS
ok      rabpic  0.014sدرنهایت امیدوارم از این پست لذت برده باشید.. کامنت و نظر فراموش نشه!این مطلب از وبلاگ توسعه دهندگان SNIX کپی برداری شده است... لینک پست درblog.snix.ir</description>
                <category>انتشارات GoLang</category>
                <author>سینا قادری</author>
                <pubDate>Thu, 27 Jan 2022 10:43:23 +0330</pubDate>
            </item>
                    <item>
                <title>جنریک ها در گولنگ</title>
                <link>https://virgool.io/golangpub/generics-in-golang-nxjlnrgygzqf</link>
                <description>What is Go generics?حتما میدونید که گولنگ یک زبان تایپ ثابت هست, یعنی اینکه هر متغیر داخل برنامه شما باشه حتما یک تایپ از قبل مشخص شده داره. مثلا وقتی که یک فانکشن تعریف میکنیم باید حتما نوع پارامتر هایی که فانکشن میگیره رو مشخص کنیم مثل کد زیر:func Print(s string) {اینجا ما اومدیم یه پارامتر رو تعریف کردیم با اسم s و تایپ string، ما میتونیم هر تعداد پارامتر دیگه‌ای که خواستیم با هر تایپی مثل float64، int، struct تعریف کنیم. ولی مشکل اینجا بوجود میاد که نمیتونیم یک عدد به این فانکشن پاس بدیم چون عدد‌ها از جنس int هستن و نمیشه یه int توی یک متغیر string بریزیم.قبلا ما میومدیم تایپ پارامتر s رو از نوع interface تعریف می‌کردیم، که این مشکل تا حدودی حل می‌شد، ولی باز هم محدودیت‌ها زیادی داشتیم.جنریک هااینجا بود که ما برای حل این مشکل اومدیم از چیزی به اسم جنریک‌ها استفاده کردیم.بریم با هم توی کد امتحان کنیم:func PrintAnything[T any](thing T) {  fmt.Println(thing) }بهتر نشد؟ ما جنریکی به اسم T تعریف کردیم که میتونه هر تایپی رو بگیره و یک پارامتر تعریف کردیم از نوع جنریک T اینطوری میتونیم هرچیزی به این فانکشن پاس بدیم تا پرینت کنه واسمون به همین سادگی:PrintAnything(&amp;quotHello!&amp;quot)
PrintAnything(42)
PrintAnything(true)زمانی که این فانکشن فراخوانی میکنیم پارامتر thing همون لحظه با مقداری که بهش پاس میدیم تایپش مشخص میشه.جنریک تایپ ها تا اینجا که خیلی باحال بود, ما تونستیم یه فانکشن بنویسیم که میتونه یک آرگومان از هر تایپی بگیره.حالا اگر بخوایم یه تایپ بسازیم که بتونه هر نوعی داشته باشه چی؟ مثلا یه slice از هر چیزی.بله جنریک ها داخل تعریف تایپ هم کاربرد دارند ما میتونیم اینطوری این تایپ تعریف کنیم:type Bunch[E any] []Eاینجا ما میگیم که تایپ Bunch یک اسلایس از نوع مشخصی به اسم E هست, حالا خود همین E یه جنریک هست که از هر چیزی میتونه باشه برای مثال Bunch[int] یک slice از نوع int هست. مثال در کد:x := Bunch[int]{1, 2, 3}ما میتونیم از این نوع تایپ توی فانکشن ها هم استقاده کنیم:func PrintBunch[E any](b Bunch[E]) {حتی میتونه متود داشته باشه :func (b Bunch[E]) Print() {ما میتونیم یکسری محدودیت ها و شروط تعریف کنیم برای جنریک ها, مثلا میتونیم بگیم جنریک فقط string قبول کنه. مثل کد زیر:type StringableBunch[E Stringer] []Eاین قابلیت روی نسخه 1.18 به بعد گولنگ وجود داره. ( از این لینک میتونید نسخه ی 1.18-beta گولنگ دریافت کنید)اگر هم به هر دلیل نمیتونین این ورژن از گو نصب کنید میتونید از این لینک برین و داخل مرورگرتون تست کنین.امیدوارم توضیحاتم مفید بوده باشه. توضیحات تکمیلی رو می تونید توی این لینک ببینید. اگه براتون مفید بود و خوشتون اومد، لایک یادتون نره! انتقادات و پیشنهادات هم میتونید توی نظرات بهم بگین.</description>
                <category>انتشارات GoLang</category>
                <author>محمد عباسی</author>
                <pubDate>Mon, 03 Jan 2022 20:51:25 +0330</pubDate>
            </item>
                    <item>
                <title>جنریک ها در گو و بررسی پرفورمنس آنها با گرفتن بنچ مارک</title>
                <link>https://virgool.io/golangpub/%D8%AC%D9%86%D8%B1%DB%8C%DA%A9-%D9%87%D8%A7-%D8%AF%D8%B1-%DA%AF%D9%88-%D9%88-%D8%A8%D8%B1%D8%B1%D8%B3%DB%8C-%D9%BE%D8%B1%D9%81%D9%88%D8%B1%D9%85%D9%86%D8%B3-%D8%A2%D9%86%D9%87%D8%A7-%D8%A8%D8%A7-%DA%AF%D8%B1%D9%81%D8%AA%D9%86-%D8%A8%D9%86%DA%86-%D9%85%D8%A7%D8%B1%DA%A9-r8rhw88uh1xh</link>
                <description>در ماه فبریه 2022 به صورت رسمی ورژن 1.18 گو ریلیز میشه و در این ورژن اولین بار در یک ورژن stable از گو ما generics رو داریم و میتونیم ازش استفاده کنیم؛ فیچری که گوفر ها خیلی وقته منتظرش هستن.یک مثال از جنریک! جمع اعدادفرض کن در لحظه بدون جنریک میخوایم توی زبون Go آیتم های یک سری اسلایس رو با هم جمع کنیم و خروجی رو برگردونیم. جواب ساده اینه که نمیتونیم یک تابع داشته باشیم که جامع باشه. باید برای هر تایپ یک تابع بنویسیم. برای مثال:func SumInts(s []int) int {
   var sum int
   for _, num := range s {
      sum += num
   }
   return sum
}
func SumInt64s(s []int64) int64 {
   var sum int64
   for _, num := range s {
      sum += num
   }
   return sum
}

func main() {
   fmt.Println(SumInts([]int{1, 2, 3}))
   fmt.Println(SumInt64s([]int64{1, 2, 3}))
}همونطوری که توی کد بالا می بینید ما برای int64 ها باید یک تابع جدید میزدیم و دقیقا همون لاجیک جمع کردن آیتم های int رو کپی میکردیم. حالا ما چه تایپ های عددی ایی داریم؟ int, int8, int32, int64, uint, uint32, float ... . اگه بخوایم با این روش جلو بریم باید برای تک تک این تایپ ها یک تابع جمع بنویسیم.البته میتونیم با استفاده از interface{} و مقداری تف زدن :) یک تابع داشته باشیم که کار Sum رو برامون انجام بده:func Sum(s interface{}) float64 {
   switch s.(type) {
   case []int:
      return float64(SumInts(s.([]int)))
   case []int64:
      return float64(SumInt64s(s.([]int64)))
   }
   return -1
}ولی خب همونطوری که معلومه فقط در ظاهر کسی که از پکیج استفاده میکنه کارش راحت شده (جدا از اینکه چون داریم float64 میکنیم overhead داریم) اما کدمون پیچیده تر میشه و بعدا برای تعریف تایپ جدید علاوه بر تابع جدید و کپی کردن لاجیک باید case جدید هم اضافه کنیم.نصب ورژن go1.18beta1روزی که این مقاله رو مینویسم آخرین ورژن گو 1.18 بتا هست و هنوز 1.18 ریلیز نشده. برای نصب این ورژن ابتدا دستور زیر را اجرا کنید:go install golang.org/dl/go1.18beta1@latestسپس با اجرای دستور زیر منتظر بمانید تا نصب تکمیل گرددgo1.18beta1 downloadجنریک ها توی گو چطور هستن؟در مرحله اول فرض کنید میخوایم تابع Sum رو تمیز کنیم طوری که بگیم ورودی ما یک آرایه از int یا int64 هست و چون هردو خاصیت عددی دارن گو به ما اجازه میده فرایند جمع رو انجام بدیم و خروجی هم براساس تایپ ورودی برمیگردونیم که overhead نداشته باشیم.func Sum[T int | int64](s []T) T {
   var sum T
   for _, item := range s {
      sum += item
   }
   return sum
}

func main() {
   s1 := Sum([]int{1, 2, 3})
   fmt.Printf(&amp;quot%T %d\n&amp;quot, s1, s1) // int 6
   s2 := Sum([]int64{1, 2, 3})
   fmt.Printf(&amp;quot%T %d\n&amp;quot, s2, s2) // int64 6
}اول خروجی ها رو می بینیم که آره. همونطوری که انتظار داشتیم جمع درست انجام شده بود و تایپ خروجی ها براساس ورودی ها داینامیک بود! این خیلی خوبه. حالا ببینیم کدش رو چطور زدیم؟تابع رو به این شکل تعریف کردیم. Sum[T int | int64](s []T) T توی این خط مشخصه که Sum اسم تابع هست اما بین [] ما تایپ های قابل قبولمون رو با استفاده از constraints ها تعریف میکنیم. مثلا توی این تابع گفتیم ما یک تایپ T داریم که نوعش میتونه int یا int64 باشه. جلوتر گفتیم ورودی s ما از نوع اسلایس T هست و خروجی ما هم از نوع T هست. حالا وقتی توی ورودی تابع یک اسلایس int64 دادیم متوجه میشه که توی کد ما T=int64 و لاجیک ما برای یک اسلایس int64 اجرا میشه. حالا اگه بخوایم به Sum یک تایپ جدید مثلا float64 اضافه کنیم چی؟func Sum[T int | int64 | float64](s []T) T {
   var sum T
   for _, item := range s {
      sum += item
   }
   return sum
}

func main() {
   s1 := Sum([]int{1, 2, 3})
   fmt.Printf(&amp;quot%T %d\n&amp;quot, s1, s1) // int 6
   s2 := Sum([]int64{1, 2, 3})
   fmt.Printf(&amp;quot%T %d\n&amp;quot, s2, s2) // int64 6
   s3 := Sum([]float64{1, 2.5, 3})
   fmt.Printf(&amp;quot%T %f\n&amp;quot, s3, s3) // float64 6.500000
}همونطوری که توی کد واضح هست به T تایپ float64 رو هم اضافه کردیم و خیلی راحت تونستیم از تابع برای float64 ها هم استفاده کنیم.چیزی که هست اگه توجه کنید ما داریم تعریف تابع sum رو شلوغ تر میکنیم. یعنی جایی که تایپ های T رو مشخص میکنیم طولانی و طولانی تر میشه و متاسفانه reusable نیست کد ما. یعنی اگه یک تابع دیگه برای prod (حاصل ضرب آیتم ها) بخوایم بنویسیم باز باید تک تک int int64 float64 و .. ها رو دوباره بنویسیم.برای حل این مشکل میتونیم از interface ها اینطور استفاده کنیم:type numbers interface {
   int | int64 | float64
}

func Sum[T numbers](s []T) T {
   var sum T
   for _, item := range s {
      sum += item
   }
   return sum
}برای تمیز تر شدن کد توصیه میشه یک پکیج به اسم constrains داشته باشیم و این اینترفیس ها اونجا تعریف شده باشن و جا های مختلف پروژه ازشون استفاده کنیم.جنریک های Go از لحاظ پرفورمنسی چطور هستن؟بیاید با هم یک مثال رو در نظر بگیریم. میخوایم یک تابع بنویسیم که بگرده دنبال یک آیتم توی یک اسلایس و بهمون بگه ایندکسش توی اون اسلایس چنده و اگر نتونست پیداش کنه -1 برگردونه.func Find[T comparable](s []T, search T) int {
   for i, item := range s {
      if item == search {
         return i
      }
   }
   return -1
}توی این کد از comparable استفاده کردیم که یکی از کانسترین های پیشفرض زبون هست که به ما اجازه مقایسه رو میده. یعنی یک اینتفرفیس از پیش تعریف شده گو برای این منظور که شامل بولین, اعداد, متن و ... میشود:comparable is an interface that is implemented by all comparable types(booleans, numbers, strings, pointers, channels, interfaces,arrays of comparable types, structs whose fields are all comparable types).خب حالا میدونیم این کد کار میکنه. ولی خوب کار میکنه؟ پرفورمنسی چطوره؟ میخوایم با این دو تابع که مخصوص پیدا کردن یک آیتم توی اسلایس int و string هستن مقایسش کنیم.func FindStr(s []string, search string) int {
   for i, item := range s {
      if item == search {
         return i
      }
   }
   return -1
}
func FindInt(s []int, search int) int {
   for i, item := range s {
      if item == search {
         return i
      }
   }
   return -1
}برای بنچ مارک گیری یک اسلایس 1000 عضوی میسازیم و دنبال عضو 500 ام میگردیم.مقایسه خروجی برای int ها:BenchmarkFindInt       4918909               244.5 ns/op
BenchmarkFind_ForInt           4918566               245.2 ns/opهمونطوری که مشاهده میکنید تفاوت در حد یک نانوثانیه هست که واقعا قابل چشم پوشی هست. برای رشته ها هم همین حرکت رو انجام بدیم:BenchmarkFindStr        888519              1267 ns/op
BenchmarkFind_ForStr            943863              1274 ns/opباز هم می بینیم تفاوت در حد چند نانوثانیه هست که بسیار کم هست و با در نظر گرفتن اینکه چقدر کد ما رو تمیز تر کرده قابل چشم پوشی.جمع بندیبا اومدن جنریک ها به گو در خیلی از توابع به اصطلاح utility کار ما ساده تر خواهد شد. من خیلی خوشحالم چون طی توسعه خیلی نیازش رو حس میکردم. اما جنریک در گو بسیار ابتدایی میباشد و هنوز باید به رعایت اصول و معماری درست پروژه توجه ویژه ایی داشت چون جنریک با magic هایی که در زبان های Dynamic داریم بسیار متفاوت اصل و صرفا در مواردی جلوی دوباره نویسی لاجیک را میگیرد.</description>
                <category>انتشارات GoLang</category>
                <author>محمد حسینی راد</author>
                <pubDate>Sun, 02 Jan 2022 22:20:14 +0330</pubDate>
            </item>
                    <item>
                <title>اصول SOLID در زبان Go (قسمت اول-Single Responsibility)</title>
                <link>https://virgool.io/golangpub/solidingolang01-anlstxlhaqnp</link>
                <description>مقدمهاصل اول Single Responsibilityاصل دوم Open/Closedاصل سوم Liskov substitutionاصل چهارم Interface segregationاصل پنجم                            Single Responsibility principleیا اصل تک وظیفه ایسلام من علی فرهادنیا هستم،برنامه نویس و علاقه مند به دنیای تکنولوژی در این قسمت از این سری میخوام اولین اصل از اصول سالید رو در زبان گولنگ توضیح بدم.این اصل توی دنیای شی گرایی برای کلاس ها بیان شده و به طور خلاصه میگه که هر کلاس باید یک مسئولیت داشته باشه ، برای یک چیز ایجاد شده باشه و به یک دلیل تغییر کنه.ولی خب ما توی دنیای گولنگ کلاس ملاس نداریم :/پس تکلیف چیه؟خب اصلا کلاس چیه و چرا وجود داره؟تعریف من از کلاس اینه که کلاس یه قالب کدنویسیه که یه سری چیزای مرتبطو کنار هم نگه میداره و بهشون یه ماهیت خاص و گاهی یه سری رفتار میده.خب توی گولنگ یه چیزی وجود داره به نام type که با یه سینتکس به خصوص میشه انواع جدیدی از دادرو ایجاد کرد.مثلا میشه به کمک ساختار داده ای به نام structure یه سری انواع داده مختلفو کنار هم قرار داد و بهشون یه ماهیت جدید داد.و از جذابیتای زبون گولنگ اینه که میشه به کمک تابع ها برای این استراکچر ها یه سری رفتار تعریف کرد و یه سری تابعو بهشون نسبت داد.پس تا حدی میشه این اصل تک وظیفه ایو گولنگیزش کرد:)خب یه بازنویسی از این اصل برای دنیای گولنگ داشته باشیم:اصل تک وظیفه ای در زبان گولنگ یعنی هر type باید یک مسئولیت داشته باشه ، برای یک چیز خاص ایجاد شده باشه و به یک دلیل تغییر کنه.مقدمه بسه بریم ببینیم چه خبره:با یه مثال شروع میکنم:فرض کنید میخوایم یه دفترچه یادداشت (یا به قول خارجیا notepad) خیلی ساده برای خودمون بسازیم که هر وقت لازم شد بتونیم توش یه متن وارد کنیم و امکان حذف کردن متن هم داشته باشه.به نظرم امکان ذخیره کردن متن توی فایل هم داشته باشه خوبه.شاید بعدا خواستیم وصلش کنیم به یه پرینتر و هر وقت خواستیم فایلارو پرینت بگیریم.خب پس شد:ساختاری برای نگه داری متن هاقابلیت اضافه کردن متنقابلین حذف متنقابلیت ذخیره کردن توی فایلبریم تو کار پیاده سازی:برای ساختار دفترچه یادداشت از یه استراکچر ساده شامل یه آرایه از رشته ها استفاده میکنم://Notepad structure
type Notepad struct {
    notes []string //slice of strings to to keep notes
}تابعی برای اضافه کردن نوشته به دفترچه یادداشت://AddNote get string and add it to notes
func (n *Notepad) AddNote(text string) {
    n.notes = append(n.notes, text)
}تابعی برای حذف کردن یک یادداشت://RemoveNote get index and remove it from notes
func (n *Notepad) RemoveNote(index int) {
    n.notes =append(n.notes[:index], n.notes[index+1:]...)
}یه تابعم برای چسبوندن همه یادداشت ها ب هم با فرمتی که مد نظرمونه به هم مینویسیم که برای پرینت کردنو و جاهای دیگه به درد میخوره(یه چیزی مثل تابع ToString جاوا)://String join all notes and return them as one string
func (n *Notepad) String() string {
    return strings.Join(n.notes, &amp;quot\n&amp;quot)
}و در آخر تابعی برای ذخیره کردن یادداشت ها توی فایل:توجه:بعد از منتشر کردن لینک مقاله توی لینکدینم یکی از دوستان گفتن که پکیج io/ioutil هم از ورژن 1.16 به بعد کنار گذاشته شده پس من هم کامنتش میکنم و به جاش از پکیج os استفاده میکنم(همه تابع هایی که در ادامه از این پکیج استفاده کردنو تغییر میدم و کد قبلیو کامنت میکنم که مشخص باشه)//function to save notes to file
func (n *Notepad) SaveToFile&#40;path string&#41; {
      _ = os.WriteFile&#40;path, []byte(n.String(&#41;), 0644)
/*The io/ioutil package has turned out in go 1.16
     _ = ioutil.WriteFile&#40;path,
    []byte(n.ToString(&#41;), 0644)
*/
}خب تقریبا دفترچه یادداشتمونو درست کردیم حالا وقت امتحان کردنشه پس بیاین یه چنتا یادداشت بهش اضافه کنیم:func main() {
    mynotes := Notepad{} //create notepad
    //adding note to notepad
    mynotes.AddNote(&amp;quotcongratulations&amp;quot)
    mynotes.AddNote(&amp;quotBreaking the first principle was done successfully!&amp;quot)
    //save notes to file
    mynotes.SaveToFile&#40;&amp;quottest1&amp;quot&#41;
    //print notes

   fmt.Println(mynotes.String())
}خب خروجی کارو ببینیم:congratulations
Breaking the first principle was done successfully!خب ما همین الان اصل تک وظیفه ایو زیر پا گذاشتیم!ما گفتیم این اصل میگه هر type  که ایجاد میشه باید مسئول یک چیز باشه و خب دفترچه یادداشت مسئول نگه داری متنه نه نوشتن اون توی یه فایل دیگه .پس تابع  SaveToFile این اصلو زیر پا گذاشت چون به دفترچه یادداشت چسبوندیمش و گفتیم جزیی از اونهخب راه حل چیه؟سادستراه حل اینه که تابع رو به صورت مستقل تعریف کنیم(حتی کلا میشه بردش توی یه پکیج دیگه)اینجوری:func SaveToFile&#40;input string, path string&#41; {
   _ = os.WriteFile&#40;path, []byte(input&#41;, 0644)
/*The io/ioutil package has turned out in go 1.16
    _ = ioutil.WriteFile&#40;path, []byte(input&#41;, 0644)
*/
}برنامه که حالت قبلیم درست کار میکرد پس این کارا برای چیه؟خب باید به عرضتون برسونم که درسته در این برنامه کوچیک همه چی به نظر درست میاد ولی فرض کنید برنامتون خیلی بزرگ تر میشه و مثلا همین تابع ذخیره در فایل به جز این دفترچه یادداشت خیلی جاهای دیگه هم کاربرد داره و باید برای هرجا که کاربرد داره بازم بنویسیمش و... که این موضوع علاوه بر زحمت زیاد در مرحله اولیه نوشتن میتونه یه فاجعه در مرحله گسترش دادن برنامه به همراه داشته باشه(اشک ها پای همین مسئله ریخته شده:))این فقط یکی از دلایلشه و کلی دلیل دیگه هم داره که اگر خواستین بدونین به نظرم برین دنبال یادگیری مسائل مربوط به برنامه نویسی تمیز و اصولی(که البته فکر کنم کسی  که داره این مقالرو میخونه داره دنبال همین میگرده:| ولی خب توضیح بیشتر در حوصله این بحث نمیگنجه).در این مسئله حتی میشه کلا یه ماهیت جدا برای تابع ذخیره در فایل قائل شد و مثلا در اینده گسترش داد که کارهای دیگه ای مثل فرمت کردن یا ذخیره توی فضاهای ذخیره سازی ابری و ... رو پوشش بده://save structure
type Save struct {
    default_path    string
    //...
}
//function to save notes to file
func (s *Save) SaveToFile&#40;input string, path string&#41; {
    if path == &amp;quot&amp;quot {
        path = s.default_path
}
    _ = os.WriteFile&#40;path, []byte(input&#41;, 0644)
/*The io/ioutil package has turned out in go 1.16
    _ = ioutil.WriteFile&#40;path, []byte(input&#41;, 0644)
*/
}از طریق گیتهابم میتونید به فایل کلی برنامه دسترسی داشته باشین.از این لینک.توی قسمت بعدی درباره اصل دوم صحبت میکنم.بعد از انتشار قسمت دوم لینکشو اینجا قرار میدم.ممنون به خاطر وقتی که گذاشتین.</description>
                <category>انتشارات GoLang</category>
                <author>علی فرهادنیا</author>
                <pubDate>Sat, 18 Dec 2021 15:58:50 +0330</pubDate>
            </item>
                    <item>
                <title>اصول SOLID در زبان Go (قسمت صفرم-مقدمه  )</title>
                <link>https://virgool.io/golangpub/solidingolang00-kwljbshvwywg</link>
                <description>مقدمهاصل اول Single Responsibilityاصل دوم Open/Closedاصل سوم Liskov substitutionاصل چهارم Interface segregationاصل پنجمسلام دوستان من علی فرهادنیا هستم .برنامه نویس بک اند و علاقه مند به زبان گولنگ.در این سری از پست ها میخوام اصول سالیدو در حد توانم توی زبون جذاب گولنگ اجرا کنم و توضیح بدم.فکر کنم بعد خوندن این مقدمه تا حدی بفهمین که میخواین این سری پست هارو دنبال کنید یا نه:)اگر کمی با زبان گولنگ آشنایی داشته باشین(که من ب نظرم کسی که دنبال این موضوعه  این آشناییو داره) احتمالا با دیدن عنوان تعجب کردین!چون اصول سالید برای زبون های شی گرا طراحی شده و خب گولنگ زبان شی گرا نیست!ولی خب اونقدراهم غیر شی گرا نیست:/خب این یعنی چی؟!یعنیطراحان این زبون یه سری مفاهیم رو توی این زبون تعریف کردن که میشه تا حدی مشابهشو توی زبون های شی گرا پیدا کرد ولی نه کاملا!مثلا این زبون اینترفییس داره(البته تا حدی با اینترفیس زبون های شی گرا متفاوته)از اون ور ارث بری اینجا وجود ندارهو یا ایده کپسوله کردن اینجا قابل اجراس ولی نه به قدرت زبون های شی گرا.و موارد دیگه ای که در حد سوادم توی ادامه قسمت ها در جای مرتبط بهش اشاره میکنم.به همین خاطر پیاده سازی کامل اصول سالید توی این زبان تا حدی دور از انتظاره(جذابه) ولی خب توی این سری من قصد دارم تا حد امکان سعی کنم این اصولو پیاده کنم.خب اصلا چرا باید این اصولو توی زبونی مثل گولنگ یادبگیریم؟!به نظر من برای کسانی که برنامه نویسی شی گرا و اصول سالید رو بلدن این سری مطالب میتونه در درک بهتر زبون گولنگ بهشون کمک کنه(به من که کمک کرد:))و اگر صرفا مثل من کنجکاوین که این زبون جذاب تا چه حد جذابه توصیه میکنم این سریو از دست ندین:)از اونجا که این قسمت فقط مقدمس مطلب زیادی برای گفتن ندارم ودرواقع اینو نوشتم که خودمو متعهد کنم به نوشتن بقیه قسمتا و همچنین شمارو بشارت بدم به اینکه چی داخل این سری هست و چی نیست(البته تقریبا)خواستم در ادامه یه تاریخچه از سالید و عمو بابو ... بگم که به نظرم یه لینک مرتبط بذارم خیلی مفید تره تا اینکه من خودم توضیحش بدم .به نظرم اینجوری احترام بیشتری به شما و وقتتون گذاشته میشه.راستی بحث عمو باب شد اگر برنامه نویسین و تا الان کتاب clean code عمو بابو نخوندین حتما یه سری بهش بزنین پشیمون نمیشین:)و در اخر جاهای جذاب بحث از قسمت بعدی شروع میشه:)اها یه نکترو فراموش کردماگر انگلیسیتون خوبه و میخواین این مباحثو با کیفیت بیشتری پیگیری کنید منبع اصلیم برای توضیح این مباحث، این دورس.اگرم با قیمتش یا تهیه دوره به مشکل برخوردینیه سرچ توی سایتای داخلی با اسم این دوره میتونه کمک کننده باشه:)قسمت بعدی ممنون به خاطر وقتی که گذاشتین.</description>
                <category>انتشارات GoLang</category>
                <author>علی فرهادنیا</author>
                <pubDate>Fri, 17 Dec 2021 00:03:15 +0330</pubDate>
            </item>
                    <item>
                <title>چرا برای هندل‌کردن خطاها در گولنگ از RichError استفاده کنیم؟</title>
                <link>https://virgool.io/golangpub/%DA%86%D8%B1%D8%A7-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%87%D9%86%D8%AF%D9%84-%DA%A9%D8%B1%D8%AF%D9%86-%D8%AE%D8%B7%D8%A7%D9%87%D8%A7-%D8%AF%D8%B1-%DA%AF%D9%88%D9%84%D9%86%DA%AF-%D8%A7%D8%B2-richerror-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D9%85-m88nvpaq5saj</link>
                <description>توی این پست می خوام که در مورد اینکه چرا استفاده از پکیجی مثل Rich Error به ما کمک می کنه که بتونیم سرویس‌های گولنگیمونو راحت تر دیباگ کنیم توضیح بدم.قبل از هر چیزی پیشنهاد می کنم که این سخنرانی گوفرکانف در سال ۲۰۱۹ راجع به Rich Error رو ببینید. https://www.youtube.com/watch?v=4WIhhzTTd0Y شاید براتون سوال پیش بیاد که توی گو هندل کردن خطاها به خودی خود به خوبی داره انجام میشه و چرا اصلا نیاز هست که وقت بیشتری براش بزاریم. در جواب باید بگم که یکسری سوال هست که با ارور هندلینگ عادی نمیشه بهشون جواب داد و به نظر من به اگه هنوز با این سوال ها مواجه نشدید شاید این پکیج خیلی به کارتون نیاد.حالا اون سوال ها چی هستن؟معمولا وقتی که تو گو خطایی رخ میده ما اون خطا رو لاگ می کنیم تا بتونیم اونها رو بعدا پیدا کنیم و فیکسشون کنیم. و در خیلی مواقع فیکس کردن اون خطا نیاز به اطلاعات بیشتری داره تا بتونیم علت اصلی رو راحت تر پیدا کنیم. اینجا هستش که جواب این سوال ها به ما کمک می کنن.پروسه ای که منجر به این خطا شده از کجا شروع شده و بعد از طی کردن چه مراحلی به اینجا رسیده؟در هنگامی که خطا رخ داده ما چه runtime argument هایی داشتیم؟آیا لازم هست که این خطا رو لاگ کنیم؟ریسپانس مناسب وقتی که این خطا رخ میده با توجه به محیط اجرا باید چی باشه؟ خب قبل از اینکه بریم سراغ جواب این سوال ها باید بگم که هندل کردن خطاها توی گو می تونه به صورت panic &amp; recover یا به صورت شرطی باشه. من اینجا هیچ کاری با حالت اول ندارم و فقط تمرکزم بر روی حالت شرطی هست و بحث راجع به اینکه کدوم حالت مناسب‌تر هست بستگی به خیلی شرایط داره که خارج از موضوع این مطلب هست.پروسه ای که منجر به این خطا شده از کجا شروع شده و بعد از طی کردن چه مراحلی به اینجا رسیده؟بیاید اینجوری در نظر بگیریم که ما توی اپلیکیشنمون یکسری لایه های مختلف داریم که بر روی هم قرار گرفتن و پروسه از بالاترین لایه شروع میشه به سمت لایه های زیرین میره (این لایه ها میتونن صرفا یکسری فانکشن داخل یکسری پکیج باشن) و وقتی خطایی رخ میده، اون خطا به سمت لایه های بالاتر هدایت میشه تا در نهایت در لایه‌ی اول (لایه‌ی delivery) تصمیم مناسب براش گرفته بشه.به زبان ساده‌تر خطا در پایین‌ترین لایه ساخته میشه و به لایه‌ی قبلی خودش پاس داده میشه، ما لازم داریم تا توی هر لایه بهش اسم اون لایه یا فانکشن رو تزریق کنیم تا بتونیم بعدا اون مسیری که طی شده رو ردیابی کنیم. اینجوری میشه که توی لایه های بالاتر ما اصطلاحا خطا رو chain می کنیم.شاید با خودتون بگید که معمولا این مسیرها یکسان هستن و نیازی به اینکار نباشه و خب در خیلی مواقع به این صورت نیست، برای مثلا در نظر بگیرید که یک فانکشن دارید که وظیفه‌ی ارسال ایمیل رو بر عهده داره و امکان داره که از خیلی جاها صدا زده بشه.در هنگامی که خطا رخ داده ما چه runtime argument هایی داشتیم؟حتما شما هم تا حالا با این اتفاق مواجه شدید که بخاطر یکسری دیتاهای خاص در بعضی مواقع قسمت‌هایی از سرویستون خطا بده. کاری به این نداریم که چرا اصلا باید این اتفاق بیوفته ولی اونچه که به ما کمک می کنه این هست که بدونیم اون دیتاهای خاص چی بودن که بتونیم بعد از فیکس کردن اون سناریو ها رو به تست‌هامون اضافه کنیم.یه مثال خیلی ساده بخوام بزنم مثلا شما یه قسمت ثبت نام دارید که کاربرها باید بیان و شماره موبایلشون رو وارد کنن و یکسری فرمت‌های خاص رو شما کاور نکردید، مثلا اگه کاربر شمارشو به صورت +۹۸۹..... وارد کنه اون فانکشن خطا میده. اینجا هست که ما وقتی داریم خطا رو می‌سازیم (یا وقتی chain می کنیم) می تونیم به اون یکسری meta data اضافه کنیم.آیا لازم هست که این خطا رو لاگ کنیم؟خب احتمالا شما هم با این سناریو زیاد مواجه شدید که در هر لایه ای از اپلیکیشنتون توی یک فانکشن خاص با خطاهای متفاوتی مواجه بشید. و وقتی که این خطا به لایه‌ی بالاتر برمی گرده اون لایه‌ی والد هیچ ایده‌ای نداره که این خطا از چه نوعی هست. یک مثال سادش این هست که فرض کنید یک فانکشن داریم که قرار هست دیتای ورودی رو validate کنه و توی همون فانکشن هم امکان داره که در هنگام کار خطاهای دیگه ای رخ بده. یا یک مثال دیگه این هست که شما می خواید اطلاعات یک رکورد رو از دیتابیس بگیرید و امکان داره خود این پروسه با خطا مواجه بشه و یا امکان داره که اون کوئری اصلا هیج رکوردی رو برنگردونه که اون هم در نهایت خطا محسوب میشه اما نوعش با قبلی کاملا متفاوت هست.اینجاست که میشه خطاها رو در مبدا دسته بندی کرد تا در لایه های بالاتر با توجه به نوع اونها اقدام لازم اعم از لاگ کردن یا نمایش ریسپانس به کاربر رو انجام داد. من خطاها رو به این دسته بندی ها تقسیم کردم:نوع Invalid که معمولا نشان دهنده‌ای این هست که اطلاعات ورودی صحیح نیست.نوع Forbidden که همونطور که از اسمش مشخصه نشانگر این هست که کاربر اجازه دسترسی نداره.نوع Notfound که این هم از اسمش مشخصه و مثلا توی اون مثالی که بالا زدم وقتی استفاده میشه که نتیجه ای وجود نداشته باشه.نوع Unexcpected: که برای مواقعی قرار میگیره که خطای غیرمنتظره‌ای رخ میده و اگه ما هنگام ساخت خطا نوعی واسش در نظر نگیریم این نوع براش انتخاب میشه.نوع Unavailable که معمولا در رابطه با سرویس های خارجی بیشتر رخ میده.این رو هم فراموش نکنیم که این دسته بندی خیلی عمومی هست و شاید بنا به نیاز هر اپی شاید کم یا زیاد بشه.حالا اگه خطایی که رخ میده از نوع notfound باشه شاید ما فقط به کاربر یه ریسپانس نشون بدیم و اصلا نیازی نباشه که اون رو لاگ کنیم.ریسپانس مناسب وقتی که این خطا رخ میده با توجه به محیط اجرا باید چی باشه؟این قسمتی هست که هیج ربطی به این پکیج نداره و نیاز هست که خود شما در بالاترین لایه براش تصمیم بگیرید که آیا می خواید این رو لاگ کنید یا فقط ریسپانس بدید و اینکه اون کار رو به چه صورت انجام بدید. تنها کمکی که این پکیج در اینجا می کنه این هست که تمام موارد بالا رو می تونه به صورت خام یا پروسس شده بهتون تحویل بده تا مابقی کار رو شما روش انجام بدید.یه مدل از خروجی:لاگ یک خطای unexpectedاینجا من کمی راجع به این عکس توضیح میدم، گرچه تا حدودی گویا هست. اینطور که مشخصه این خطا توسط یک کرون جاب ران شده که سرویس notifier بوده و بعد بخاطر خطایی که توی مرحله بعد خورده در تلاش چهارم نتونسته که اون کار رو انجام بده. خطایی هم که بوده این بوده که نتونسته به دیتابیس وصل بشه چون دیتابیس دان بوده.  شروع خطا هم در خط۲۳۱ از فایل مربوطه بوده! :)شاید براتون سوال پیش بیاد که چرا این پکیج از اینترفیس اصلی خطا در گولنگ تبعیت (implement) نمی کنه؟دلیل این کار این هست که هنگام دولوپ امکان اینکه یه خطایی به اشتباه به جای اینکه chain بشه دوباره ساخته بشه زیاد هست، ولی با استفاده از متدها با ورودی‌های مشخص، به سادگی جلوی این اشتباه گرفته میشه.در انتها پیشنهاد می کنم که یک نگاهی به سورس کد در گیت‌هاب بندازید، در اونجا توضیحات بیشتری درباره‌ی نحو‌ی استفاده‌ از پیکج داده شده. https://github.com/p3ym4n/re </description>
                <category>انتشارات GoLang</category>
                <author>پیمان گلدسته</author>
                <pubDate>Fri, 26 Nov 2021 11:34:49 +0330</pubDate>
            </item>
                    <item>
                <title>چرا خوبه که Golang رو یاد بگیریم؟</title>
                <link>https://virgool.io/golangpub/%DA%86%D8%B1%D8%A7-%D8%AE%D9%88%D8%A8%D9%87-%D8%B2%D8%A8%D8%A7%D9%86-%DA%AF%D9%88-%DB%8C%D8%A7%D8%AF-%D8%A8%DA%AF%DB%8C%D8%B1%DB%8C%D9%85-qyw0psxigogs</link>
                <description>http://kirael-art.deviantart.com/art/Go-lang-Mascot-458285682این نوشته ترجمه پست Keval Patel در این آدرس هست: https://medium.com/@kevalpatel2106/why-should-you-learn-go-f607681fad65همچنین کامنت یکی از کاربران رو در آخر همین مقاله قرار دادم که به نظرم مفید واقع می‌شود.در چند سال گذشته, زبان برنامه نویسی جدیدی ظهور کرده است: Go یا GoLang. هیچ چیز مثل یک زبون برنامه نویسی جدید یه دولوپر رو دیوونه نمیکنه, درسته؟ پس, من شروع کردم به یادگیری Go از ۴ یا ۵ ماه پیش و الان اینجام تا به شما بگم چرا خوبه که این زبان جدید رو یاد بگیریم.من در این مقاله نمی‌خواهم به شما یاد بدم چطور یه &quot;!!Hello, World&quot; بنویسید. توی فضای اینترنت پر هست از این دست آموزش‌ها. من اینجام تا توضیح بدم چرا به زبون جدید Go نیاز داریم؟. بخاطر اینکه اگر هیچ مشکلی وجود نداشته باشه به راه حل‌ای هم نیاز نداریم, درسته؟محدودیت های سخت افزاری:قانون مور در حال شکستن است.پ.ن: این قانون به صورت خلاصه میگه که هر ۲ سال تعداد ترانزیستور‌های روی یک تراشه دو برار می‌شود به این معنا که ابعاد آنها در هر ۲ سال در حال نصف شدن است.اولین پردازنده Pentium 4 با سرعت 3.0GHz در سال ۲۰۰۴ توسط اینتل معرفی شد. امروز, Macbook Pro 2016 من سرعت پردازشی حدود 2.9GHz دارد. پس, در یک دهه اخیر, قدرت پردازش زیادی بدست نیامده است. شما میتونید مقایسه افزایش قدرت پردازش همراه با زمان آن را در نمودار زیر ببینید.در نمودار بالا می‌بینید که عملکرد single-thread و فرکانس پردازنده در یک دهه ثابت مانده. اگر شما فکر می‌کنید که اضافه کردن ترانزیستورهای بیشتر راه حل هست, پس شما اشتباه میکردید.پ.ن: ببینید طبق قانون مور که بالاتر گفتم, ابعاد ترانزیستورها هر ۲ سال نصف می‌شود, و زمانی که ابعاد ترانزیستور درحال کوچک شدن هست بعد از مدتی این موضوع محدودیت‌های فیزیکی برای سازنده پردازنده‌ها ایجاد میکند.ویکیپدیا: این محدودیت فیزیکی دانشمندان را به این سمت سوق داده که شاخه‌های جدیدی از روش‌های محاسباتی را آزمایش کنند، تا در هنگام لزوم بتوانند جایگزین مناسبی برای رایانه‌های امروزی داشته باشند؛روش‌هایی همچون محاسبه کوانتومی، محاسبه زیستی و… . آنچه مسلم است، این است که در چنین رایانه‌هایی خبری از تراشه و CPU هایی به شکل‌های امروزی نخواهد بود.پس راه حل‌هایی برای مشکل بالا ارائه شد:تولید کنندگان شروع به افزودن هسته های بیشتر به پردازنده کردند. امروزه ما CPU های چهار هسته‌ای و هشت هسته‌ای در دسترس داریم.ما همچنین hyper-threading را معرفی کردیم.برای افزایش عملکرد ، حافظه کش بیشتری به پردازنده اضافه شده است.اما راه حل‌های بالا محدودیت‌های خودشون رو هم دارند. ۱ - ما نمی‌توانیم حافظه کش بیشتری را به پردازنده اضافه کنیم تا عملکرد افزایش یابد چون برای حافظه کش هم محدودیت‌های فیزیکی وجود دارد به این معنا که هرچه حافظه کش بزرگتر باشد ، سرعت آن کندتر می شود.۲ - افزودن هسته بیشتر به پردازنده, هزینه بیشتری هم دارد. همچنین ، نمی‌توان تعداد آن را به طور نامحدود افزایش داد. این پردازنده های چند هسته ای می توانند چندین Thread را به طور همزمان اجرا کنند و این موضوع برای Concurrency به ما کمک میکند که بعداً در مورد آن بحث می کنیم.بنابراین ، اگر نمی توانیم به پیشرفت های سخت افزاری متکی باشیم ، تنها راهی که می توان از آن استفاده کرد نوشتن نرم افزار کارآمدتری برای افزایش عملکرد است. اما متأسفانه ، زبان‌های برنامه نویسی مدرن خیلی کارآمد نیستند.گو, goroutine دارد:همانطور که در بالا بحث کردیم, تولیدکنندگان سخت افزار برای افزایش کارایی, هسته های بیشتری به پردازنده ها اضافه می کنند. همه دیتاسنترها بر روی آن پردازنده ها کار می کنند و ما باید در سال های آینده انتظار افزایش تعداد هسته‌ها را داشته باشیم. علاوه بر این ، برنامه های امروزی از چندین micro-service برای ارتباط با پایگاه داده ، queue ها و حافظه کش استفاده می کنند. بنابراین ، نرم افزاری که توسعه می دهیم و زبانهای برنامه نویسی که استفاده می‌کنیم باید به راحتی از Concurrency پشتیبانی کنند و با افزایش تعداد هسته ها مقیاس پذیر (scalable) باشند.اما ، اکثر زبان های برنامه نویسی مدرن (مانند جاوا ، پایتون و غیره) از دهه (’90s)زمان برنامه های  single-thread میایند. اکثر این زبان های برنامه نویسی از multi-threading می کنند. اما مشکل واقعی با اجرای برنامه های Concurrent همراه است مثل threading-locking , race conditions و deadlocks. این موارد ایجاد برنامه multi-thread را در آن زبانها را دشوار می کند.برای مثال ، ایجاد thread در جاوا از نظر حافظه کارآمد نیست. از آنجا که هر thread تقریباً 1MB از حجم حافظه را مصرف می کند و در نهایت اگر هزاران thread را ایجاد کنید ، فشار زیادی بر روی حافظه وارد می کنند و به دلیل کمبود حافظه برنامه دچار مشکل می شود. همچنین ، اگر می خواهید بین دو یا چند thread ارتباط برقرار کنید ، ایجاد این ارتباط بسیار مشکل خواهد بود.از سوی دیگر ، Go در سال 2009 هنگامی که پردازنده های چند هسته ای در دسترس بودند ، منتشر شد. به همین دلیل Go با در نظر گرفتن concurrency ساخته شده است. Go به جای thread دارای گوروتین (goroutine) است. آنها تقریباً 2 کیلوبایت حافظه از heap را مصرف می کنند. بنابراین ، می توانید میلیون ها گوروتین را در هر زمان استفاده کنید.http://golangtutorials.blogspot.in/2011/06/goroutines.html :روتین چطور کار میکند؟ منبعمزایای دیگر عبارتند از:گوروتین ها دارای stack های قابل رشد هستند. این بدان معناست که آنها فقط در صورت نیاز از حافظه بیشتری استفاده خواهند کرد.زمان راه‌اندازی (startup) گوروتین سریعتر از thread ها است.گوروتین‌ها دارای ساختار built-in برای ایجاد ارتباط بین گوروتین‌های دیگر هست که با استفاده از channel ها امکان پذیر است.گوروتین به شما این امکان را می دهد که هنگام به اشتراک گذاری ساختار داده ها ، مجبور نباشید از lock mutex استفاده کنید.همچنین گوروتین‌های گو با thread های سیستم عامل ارتباط 1:1 ندارند. این یعنی یک گوروتین میتونه روی  چندین thread اجرا بشه.شما میتونید سخنرانی Rob Pike رو برای عمیق‌تر فهمیدن این موضوع نگاه کنید:https://blog.golang.org/concurrency-is-not-parallelismبا تمام نکات بالا که Go را یک زبان بسیار قوی برای پشتیبانی از concurrency مثل java و C++/C میکنه در همین حال به زیبایی Erlang از آن استفاده می‌کند.گو در هر دو زمینه راحتی و بهینگی Concurrency به خوبی عمل کرده است.گو مستقیماً بر روی سخت افزار اجرا می شود.یکی از مهمترین مزایای استفاده از C ، C ++ نسبت به سایر زبانهای سطح بالاتر مانند جاوا/پایتون ، عملکرد آنهاست. زیرا C/C ++ کامپایل می شوند و تفسیر نمی شوند.پردازنده ها باینری را می فهمند. به طور کلی ، وقتی برنامه ای را با کامپایلر پروژه خود با استفاده از جاوا یا سایر زبان های مبتنی بر JVM می سازید ، کد خوانا برای انسان را به byte-code کامپایل می کند که توسط JVM یا سایر ماشین های مجازی که در بالای سیستم عامل اصلی اجرا می شوند. در حین اجرا ، VM آن byte-code هارا تفسیر کرده و آنها را به Binary تبدیل می کند که پردازنده ها می توانند آن را پردازش کنند.مراحل اجرای برنامه تحت VMدر طرف دیگر ، C/C ++ روی ماشین های مجازی اجرا نمی شود و این یک مرحله از چرخه اجرا را حذف کرده و عملکرد را افزایش می دهد. این کد بطور مستقیم سورس کد را برای Binary کامپایل می کند.مراحل کامپایل برنامه بدون VMاما مدیریت حافظه در آن زبان ها دردسر بزرگی است. در حالی که اکثر زبان های برنامه نویسی با استفاده از الگوریتم Garbage Collector یا Reference Counting مقداردهی و حذف شی را مدیریت می کنند.گو در هر دو زمینه به خوبی عمل کرده است. هم مانند زبان های سطح پایین مثل C++/C کامپایل می‌شود. که کارایی گو را به زبان‌های سطح پایین‌تر نزدیک می‌کنم. و همچنین از Garbage collection برای مدیریت حافظه استفاده می‌کند.نگهداری (maintain) کد نوشته شده با Go آسان است.بزارید یک چیزی به شما بگویم. Go مانند دیگر زبانها syntax برنامه نویسی دیوانه واری ندارد و دارای syntax بسیار مرتب و تمیز است.پ.ن: این مورد مزیت و معایب خودش رو داره که در ادامه توضیح می‌دهم.طراحان Go در گوگل هنگام ساخت این زبان به این نکته توجه داشتند. از آنجایی که google کد بیس بسیار بزرگی دارد و هزاران توسعه دهنده بر روی همان کد بیس کار می کردند ، درک کد برای توسعه دهندگان دیگر باید ساده باشد و یک بخش کد باید کمترین side effect (تداخل شاید بشه معنی کرد!) را روی بخش‌های دیگر داشته باشد. این باعث می شود کد به راحتی قابل نگهداری و اصلاح شود.گو عمداً بسیاری از قابلیت های زبان های OOP مدرن را کنار می گذارد.گو از class ها استفاده نمی‌کند. همه چیز به چندین package تقسیم می‌شود. گو struct داره بجای کلاس‌ها.از ارث‌بری پشتیبانی نمی‌کند. این باعث می شود کد به راحتی قابل تغییر باشد. در زبانهای دیگر مانند جاوا/پایتون ، اگر کلاس ABC از کلاس XYZ ارث‌بردی کند و شما تغییراتی در کلاس XYZ ایجاد کنید ، ممکن است در کلاسهای دیگری که XYZ را به ارث برده اند side effect ایجاد کند. گو با حذف وراثت ، درک کد را نیز آسان می کند (زیرا هنگام نگاه کردن به یک کد ، هیچ super classای وجود ندارد که بتوان به آن نگاه کرد).بدونِ constructors.بدونِ annotations.بدونِ generics.بدونِ exceptions.پ.ن: هر کدام از این بدونِ‌ها :) دلایل خودشون رو دارند که در این مقاله نمی‌گنجه.نکات بالا گو را بسیار متفاوت از زبان‌های برنامه نویسی دیگر می کند و باعث می شود برنامه نویسی در گو هم متفاوت از زبان‌های دیگر باشد. ممکن است برخی از نکات بالا را دوست نداشته باشید. اما ، اینطور نیست که شما نتوانید برنامه خود را بدون ویژگی های بالا  بنویسید. تنها کاری که باید انجام دهید این است که 2-3 خط بیشتر بنویسید. اما در جنبه مثبت ، کدِ شما را تمیزتر می کند و وضوح بیشتری به کد شما می بخشد.جایگاه زبان‌ها بر اساس کد خوانا در برابر کد بهینهدر نمودار بالا نمایش داده می شود که گو تقریباً به اندازه C/C ++ کارآمد است ، در حالی که syntax کد را مانند Ruby ، Python و سایر زبانها ساده نگه می‌دارد. این یک موقعیت برد-برد هم برای انسان‌ها و هم برای پردازنده‌ها است !!!گو توسط Google پشتیبانی می‌شود.من می دانم که این یک مزیت فنی نیست. اما ، گو توسط Google طراحی و پشتیبانی می شود. گوگل دارای یکی از بزرگترین زیرساخت های ابری در جهان است و به طور گسترده ای مقیاس بندی شده است. گو توسط گوگل برای حل مشکلات پشتیبانی از مقیاس پذیری و اثربخشی طراحی شده است. اینها همان مشکلاتی است که هنگام ایجاد سرورهای با آنها روبرو خواهینم شد.گو همچنین توسط شرکت‌های بزرگ دیگر استفاده می‌شود که در لینک زیر می‌تونید اسامی برنامه‌ها شرکت‌ها و کاربرد استفاده ‌گو در آن را مطالعه کنید. (https://github.com/golang/go/wiki/GoUsers) خلاصه:گو عملکرد بسیار بالایی مثل زبان‌های C++/C, مدیریت Concurrency مثل جاوا و سیتنکس باحالی مثل پایتون و پرل داره. اگر برنامه ای برای یادگیری Go ندارید ، باز هم می گویم محدودیت سخت افزاری به ما ، توسعه دهندگان نرم افزار فشار می آورد تا کد فوق العاده کارآمدی (efficient) بنویسند. توسعه دهنده باید سخت افزار را بشناسد و برنامه خود را مطابق آن بهینه سازی کند. نرم افزار بهینه سازی شده می تواند بر روی سخت افزار ارزان تر و کندتر (مانند دستگاه های IOT) اجرا شود و در کل تأثیر بهتری بر تجربه کاربر نهایی بگذارد.کامت یکی از کاربران که می‌تونه مفید باشه:Rex Kerr:گو جنبه های منفی زیادی نیز دارد که بیشتر آنها را به عنوان موارد مثبت ذکر کرده اید. این بدان معنا نیست که گو ارزش یادگیری ندارد (زبان سختی که نیست! چرا که نه!) ، اما این بدان معناست که پروژه های زیادی وجود دارد که نمی خواهید از گو برای آن استفاده کنید.۱- گو مستقیماً بر روی سخت افزار اجرا می شود بدون اینکه نیاز باشه به سخت افزار کاری داشته باشید ، به طور متوسط ​​سریعتر از جاوا نیست (به benchmarkهای مختلف و Computer Languages Benchmark Game مراجعه کنید). اگر واقعاً می خواهید هر گونه عملکردی را روی سخت افزار خود انجام دهید ، باید از C ، C ++ ، Rust یا برخی از زبان های دیگر که کنترل مناسب را به شما می دهد ، استفاده کنید.۲- قابلیت های abstraction گو عملاً وجود ندارد. شما می توانید از این زبان برای * انجام * کارها استفاده کنید اما نه برای ایجاد structureهای پیشرفته تر. نکته مثبت - فهم آسان آن است! نکته منفی - ساخت پروژه هایی با structure پیچیده برای همیشه دور از دسترس هستند ، زیرا ایجاد آنها بسیار دشوار است و کامپایلر به شما کمک نمی کند. در مقابل ، زبان هایی مانند C++ ، Scala ، Haskell و غیره مکانیسم های abstraction بسیار قدرتمندی را ارائه می دهند تا به کامپایلر شما بفهماند راه حل انتراعی شما برای مشکل پیچیده چیست تا کامپایلر به شما کمک کند.۳- گو فقط دارای گوروتین برای همزمانی است. اگر مشکل شما با آن مدل Concurrency به خوبی حل شد ، عالی است! اگر نه ، خوب ، این تنها مدل شماست. سایر زبانها معمولاً ترکیبی از چنین مواردی را ارائه می دهند. گو گوروتین ها را به خوبی انجام می دهد ، بنابراین اغلب می توانید از آنها در مکانهایی استفاده کنید که فکر می کنید به چیز دیگری احتیاج دارید (به عنوان مثال در یک atomic reference).بنابراین گو عملکردی در سطح جاوا (نه در سطح ++C) با یک رویکرد عالی برای  Concurrency ، و زبانی جمع و جور ، مرتب و غیرقابل انعطاف را برای شما فراهم می کند. خوب!پروژه های زیادی وجود دارد که دقیقاً گو همان چیزی است که شما می خواهید.</description>
                <category>انتشارات GoLang</category>
                <author>Taha Ahmadi</author>
                <pubDate>Tue, 21 Sep 2021 17:39:57 +0430</pubDate>
            </item>
                    <item>
                <title>آرایه و Slice در گولنگ</title>
                <link>https://virgool.io/golangpub/array-and-slices-in-golang-l6ye1tbzuckj</link>
                <description>آرایهآرایه مجموعه ای از عناصر است که به یک نوع تعلق دارند. به عنوان مثال، مجموعه اعداد صحیح 5، 8 ، 9 ، 79 و 76 یک آرایه را تشکیل می دهد. تریکب کردن مقادیر از انواع مختلف  به عنوان مثال، یک آرایه که هم رشته دارد و هم عدد صحیح، در Go مجاز نیست.اندازه آرایه کاملا مشخص بوده به طوری که این مقدار در زمان کامپایل باید ثابت باشد. تعریف آرایهیک آرایه به نوع [n] T تعلق دارد. n تعداد عناصر موجود در یک آرایه را نشان می دهد و T نوع هر عنصر را نشان می دهد. تعداد عناصر n نیز قسمتی از نوع آن است (در ادامه با جزئیات بیشتری در این مورد بحث خواهیم کرد)روش های مختلفی برای اعلام آرایه ها وجود دارد. باهم تک تک آنها را بررسی می کنیم.func main() {  
    var a [3]int //int array with length 3
    fmt.Println(a)
}عبارت var a [3] int یک آرایه صحیح را به طول ۳ تعریف می کند. به همه عناصر یک آرایه به طور خودکار مقدار صفر نوع آرایه اختصاص می یابد. در این حالت a یک آرایه صحیح است و از این رو  به تمام عناصر a، مقدار صفر int که  0 است اختصاص می یابد. خروجی اجرای دستور پرینت برنامه فوق چنین خواهید بود: [0 0 0]ایندکس آرایه با ۰ شروع می شود و ۱- آخرین ایندکس آن می باشد. اگر بخواهیم به آرایه مثال بالا مقدار  اساین کنیم، چنین عمل می کنیم:var a [3]int //int array with length 3
 a[0] = 12 // array index starts at 0
 a[1] = 78
 a[2] = 50
 fmt.Println(a)خروجی قطعه کد فوق:[12 78 50]می تواتیم برای تعریف آرایه ها از نوع میانبر آن به صورتshort hand declaration (یعنی روش کوتاه) عمل کنیم.بدین صورت که می بینید:a := [3]int{12, 78, 50}                 // short hand declaration to create array نیازی نیست که در هنگام تعریف آرایه به شکل بالا همه عناصر یک آرایه مقدار داده شود.package main
import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    a := [3]int{12} 
    fmt.Println(a)
}در برنامه فوق در خط شماره ۸ a: = [3] int {12} آرایه ای به طول ۳ را اعلام می کند اما فقط با  مقدار ۱۲ پر می شود. ۲ خانه باقی مانده به طور خودکار 0 تعیین می شود. خروجی قطعه کد فوق:[12 0 0]نکته‌ای که باید بهش اشاره کرد اینه که مقدار دادن به خونه‌ای از آرایه که  وجود نداره باعث ایجاد خطا می شود.نکته: جهت راحتی کار میشه به جای عدد  ازسه نقطه ... استفاده کرد با این  قابلیت در زمان کامپایل سایز آرایه توسط مقادیر Initialize شده حساب می‌شود:a := [...]int{2, 9, 5} //... makes the compiler determine the lengthاندازه آرایه بخشی از نوع آن است. از این رو [5] int و [25] int انواع متمایزی هستند. به همین دلیل، اندازه آرایه ها قابل تغییر نیست. نگران این محدودیت نباشید زیرا slice ها به کمک ما می آیند.آرایه ها value type هستندآرایه ها در Go انواع مقداری هستند(value types) و انواع مرجعی (reference types) نیستند. این به این معنی است که وقتی آنها به یک متغیر جدید اختصاص می یابند، یک کپی از آرایه اصلی به متغیر جدید اختصاص می یابد. اگر تغییراتی در متغیر جدید ایجاد شود، در آرایه اصلی منعکس نمی شود.package main

import &amp;quotfmt&amp;quot

func main() {  
    a := [...]string{&amp;quotTEH&amp;quot, &amp;quotMHD&amp;quot, &amp;quotAWZ&amp;quot, &amp;quotIFN&amp;quot, &amp;quotSYZ&amp;quot}
    b := a // a copy of a is assigned to b
    b[0] = &amp;quotADU&amp;quot
    fmt.Println(&amp;quota is &amp;quot, a)
    fmt.Println(&amp;quotb is &amp;quot, b) 
}در برنامه فوق در خط شماره ۷، یک نسخه از a به b اختصاص داده شده است. در خط شماره ۸ اولین عنصر b به ADU تغییر کرده ولی این در آرایه اصلی (همان a) منعکس نشده است. a is [TEH MHD AWZ IFN SYZ]  
 b is [ADU MHD AWZ IFN SYZ]به همین علت وقتی آرایه ها به عنوان پارامتر به توابع منتقل می شوند، آنها از نظر مقدار(passed by value) منتقل می شوند و آرایه اصلی بدون تغییر می ماند. package main

import &amp;quotfmt&amp;quot

func changeLocal(num [5]int) {  
    num[0] = 55
    fmt.Println(&amp;quotinside function &amp;quot, num)

}
func main() {  
    num := [...]int{5, 6, 7, 8, 8}
    fmt.Println(&amp;quotbefore passing to function &amp;quot, num)
    changeLocal(num) //num is passed by value
    fmt.Println(&amp;quotafter passing to function &amp;quot, num)
}در برنامه فوق در خط شماره ۱۳   آرایه num در واقع به صورت pass by value به تابع changeLocal منتقل می شود وبه همین مقادیر اصلی آن بعد صدا زدن آرایه هیچ تغییری نخواهد کرد.before passing to function  [5 6 7 8 8]  
 inside function  [55 6 7 8 8]  
 after passing to function  [5 6 7 8 8]طول یک آرایهطول آرایه با پاس دادن  آرایه به عنوان پارامتر به تابع len پیدا می شود.package main

import &amp;quotfmt&amp;quot

func main() {  
    a := [...]float64{67.7, 89.8, 21, 78}
    fmt.Println(&amp;quotlength of a is&amp;quot,len(a))
}خروجی برنامه فوق بدین صورت می باشد:length of a is 4تکرار (iterate) روی عناصر آرایه ها همانطور که انتظار می رود میتوان از حلقه for می توان برای تکرار عناصر آرایه استفاده کرد.package main

import &amp;quotfmt&amp;quot

func main() {  
    a := [...]float64{67.7, 89.8, 21, 78}
    for i := 0; i &lt; len(a); i++ { //looping from 0 to the length of the array
        fmt.Printf(&amp;quot%d th element of a is %.2f\n&amp;quot, i, a[i])
    }
}برنامه فوق از یک حلقه for برای تکرار عناصر آرایه از شاخص 0 تا طول آرایه منهای یک استفاده می کند. خروجی کد فوق بدین صورت می باشد:0 th element of a is 67.70  
1 th element of a is 89.80  
2 th element of a is 21.00  
3 th element of a is 78.00گولنگ با استفاده از range روشی بهتر و مختصر برای تکرار در یک آرایه ارائه می دهد. range هم ایندکس و هم مقدار آن ایندکس را برمی گرداند. بیایید کد بالا را با استفاده از range بازنویسی کنیم و همچنین مجموع تمام عناصر آرایه را کنیمpackage main

import &amp;quotfmt&amp;quot

func main() {  
    a := [...]float64{67.7, 89.8, 21, 78}
    sum := float64(0)
    for i, v := range a {//range returns both the index and value
        fmt.Printf(&amp;quot%d the element of a is %.2f\n&amp;quot, i, v)
        sum += v
    }
    fmt.Println(&amp;quot\nsum of all elements of a&amp;quot,sum)
}خط شماره  کد بالا for i, v := range a حالت range  حلقه for است. هم ایندکس و هم مقدار آن شاخص را برمی گرداند. مقادیر را چاپ می کنیم و همچنین مجموع تمام عناصر آرایه a را محاسبه می کنیم. خروجی برنامه:0 the element of a is 67.70  
1 the element of a is 89.80  
2 the element of a is 21.00  
3 the element of a is 78.00

sum of all elements of a 256.5درصورتی که فقط مقدار می خواهید و می خواهید ایندکس را نادیده بگیرید، می توانید این کار را با جایگزینی متغیر ایندکس با شناسه _ خالی انجام دهید.for _, v := range a { //ignores index  
 }  حلقه for فوق ایندکس را نادیده می گیرد. به همین ترتیب مقدار نیز قابل چشم پوشی است. (خاطرتان حتما هست که در گولنگ اگر از متغیری که تعریف کردید استفاده نکنید با خطا مواجه می شوید. پس این نادیده گرفتن متغیرها کاملا طبیعی می باشد)آرایه های چند بعدیآرایه هایی که ما تاکنون ایجاد کرده ایم همه تک بعدی هستند. ایجاد آرایه های چند بعدی امکان پذیر است.package main

import (  
    &amp;quotfmt&amp;quot
)

func printarray(a [3][2]string) {  
    for _, v1 := range a {
        for _, v2 := range v1 {
            fmt.Printf(&amp;quot%s &amp;quot, v2)
        }
        fmt.Printf(&amp;quot\n&amp;quot)
    }
}

func main() {  
    a := [3][2]string{
        {&amp;quotlion&amp;quot, &amp;quottiger&amp;quot},
        {&amp;quotcat&amp;quot, &amp;quotdog&amp;quot},
        {&amp;quotpigeon&amp;quot, &amp;quotpeacock&amp;quot}, //this comma is necessary. The compiler will complain if you omit this comma
    }
    printarray(a)
    var b [3][2]string
    b[0][0] = &amp;quotapple&amp;quot
    b[0][1] = &amp;quotsamsung&amp;quot
    b[1][0] = &amp;quotmicrosoft&amp;quot
    b[1][1] = &amp;quotgoogle&amp;quot
    b[2][0] = &amp;quotAT&amp;T&amp;quot
    b[2][1] = &amp;quotT-Mobile&amp;quot
    fmt.Printf(&amp;quot\n&amp;quot)
    printarray(b)
}در برنامه فوق در خط شماره ۱۷ آرایه رشته ای دو بعدی a با استفاده از سینتکس short hand (که بالاتر توضیح دادیم)اعلام شده است.(comma در انتهای خط شماره 20 لازم است) آرایه دو بعدی دیگر به نام b در سطر شماره ۲۳ تعریف می شود  و string ها برای هر ایندکس یکی یکی به آن اضافه می شوند. این روش دیگری برای مقداردهی اولیه آرایه دو بعدی است است. فانکشن printarray در خط شماره ۷ برای چاپ محتویات آرایه های  دوبعدی از دو حلقه range استفاده می کند. برنامه فوق چاپ خواهد کرد:lion tiger  
cat dog  
pigeon peacock 

apple samsung  
microsoft google  
AT&amp;T T-Mobileبه نظرم در مورد آرایه ها تا اینجا کافیه! موافقید !؟  اگرچه آرایه ها به اندازه کافی انعطاف پذیر به نظر می رسند اما با محدودیت طول ثابت ارائه می شوند. افزایش طول یک آرایه امکان پذیر نیست. این جایی است که slice ها وارد بازی می شوند. در واقع در Go اسلایس ها خیلی رایج تر از آرایه ها هستند. در ادامه آنها را توضیح می دهیم. اسلایس (slice) در گولنگیک slice در واقع یک wrapper راحت، انعطاف پذیر و قدرتمند برای  آرایه است. slice ها به خودی خود هیچ داده ای ندارند. آنها فقط ارجاعات به آرایه های موجود هستند.ایجاد یک sliceیک slice با عناصر نوع T با [] T نشان داده می شودpackage main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    a := [5]int{76, 77, 78, 79, 80}
    var b []int = a[1:4] //creates a slice from a[1] to a[3]
    fmt.Println(b)
}سینتکس a[start:end] اسلایسی از آرایه a ایجاد می کند که از ایندکس start می شود تا ایندکس end-1. بنابراین در خط شماره 9 از برنامه فوق  [4: 1] نمایش آرایه a را با شروع از ایندکس های 1 تا 3 ایجاد می کند. از این رو اسلایس b دارای مقادیر [ 79 78 77 ] است. به یک روش  دیگر هم برای ایجاد یک slice نگاه کنیم.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    c := []int{6, 7, 8} //creates and array and returns a slice reference
    fmt.Println(c)
}در برنامه فوق در خط شماره ۹، c: = [] int {6، 7، 8} آرایه ای با ۳ عدد صحیح ایجاد می کند و یک reference اسلایس را که در c ذخیره شده است برمی گرداند.تغییر یک sliceیک اسلایس به خودی خود هیچ داده ای ندارد بلکه  فقط فقط رفرنسی نمایشی به آرایه زمینه ای است. هرگونه تغییری که در slice ایجاد شود، در آرایه زیرین منعکس خواهد شد.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
    dslice := darr[2:5]
    fmt.Println(&amp;quotarray before&amp;quot,darr)
    for i := range dslice {
        dslice[i]++
    }
    fmt.Println(&amp;quotarray after&amp;quot,darr) 
}در خط شماره ۹ برنامه فوق، از شاخص های 2 ، 3 ، 4 آرایه dslice ایجاد می کنیم. حلقه for مقدار این ایندکس ها را یکی افزایش می دهد. وقتی آرایه را بعد از حلقه for چاپ می کنیم، می توانیم ببینیم که تغییرات slice در آرایه منعکس شده است. خروجی برنامه:array before [57 89 90 82 100 78 67 69 59]  array after [57 89 91 83 101 78 67 69 59]  می بینید که با توجه به تغییرات اسلایس مقادیر آرایه اصلی هم تغییر پیدا کرده اند. مقادیر ایندکس های2، 3 و 4 هر کدام یکی بیشتر شده اند. (91, 83, 101)هنگامی که تعدادی از اسلایس ها آرایه اصلی یکسانی دارند، تغییراتی که هر یک ایجاد می کند در آرایه منعکس می شود.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    numa := [3]int{78, 79 ,80}
    nums1 := numa[:] //creates a slice which contains all elements of the array
    nums2 := numa[:]
    fmt.Println(&amp;quotarray before change 1&amp;quot,numa)
    nums1[0] = 100
    fmt.Println(&amp;quotarray after modification to slice nums1&amp;quot, numa)
    nums2[1] = 101
    fmt.Println(&amp;quotarray after modification to slice nums2&amp;quot, numa)
}در خط شماره ۹ در numa [:] مقادیر شروع و پایان وجود ندارد. مقادیر پیش فرض برای شروع و پایان به ترتیب 0 و len (numa) است. هر دو برش nums1 و nums2 یک آرایه مشترک دارند. خروجی برنامه:array before change 1 [78 79 80]  
array after modification to slice nums1 [100 79 80]  
array after modification to slice nums2 [100 101 80]از خروجی واضح است که وقتی اسلایس ها آرایه یکسانی دارند. تغییرات ایجاد شده در اسلایس در آرایه منعکس می شود.طول و ظرفیت یک اسلایس طول(length) یک slice تعداد عناصر موجود در آن است و ظرفیت(capacity) slice تعداد عناصر موجود در آرایه زیرین است که از نمایه ای که برش از آن ایجاد می شود شروع می شود.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    fruitarray := [...]string{&amp;quotapple&amp;quot, &amp;quotorange&amp;quot, &amp;quotgrape&amp;quot, &amp;quotmango&amp;quot, &amp;quotwater melon&amp;quot, &amp;quotpine apple&amp;quot, &amp;quotchikoo&amp;quot}
    fruitslice := fruitarray[1:3]
    fmt.Printf(&amp;quotlength of slice %d capacity %d&amp;quot, len(fruitslice), cap(fruitslice)) //length of fruitslice is 2 and capacity is 6
}در برنامه فوق ، fruitslice از شاخص 1 و 2 fruitarray ایجاد می شود. از این رو طول fruitslice برابر ۲ است. طول آرایه fruitarray برابر ۷ برابر است. برنج میوه از شاخص 1 آرایه ایجاد شده است. از این رو ظرفیت میوه میوه تعداد عناصر موجود در مجموعه میوه ای است که از شاخص 1 یعنی نارنجی شروع می شود و این مقدار 6 است. از این رو ظرفیت میوه میوه 6 است. برنامه طول قطعه 2 ظرفیت 6 را چاپ می کند. یک قطعه را می توانید مجدداً به ظرفیت خود برش دهید. هر چیزی فراتر از آن باعث می شود برنامه خطای زمان اجرا ایجاد کند.ایجاد اسلایس ها با استفاده از فانکشن makeاز سینتکس func make ([] T ، len ، cap) [] T می توان با پاس دادن نوع، طول و ظرفیت یک  slice ایجاد کرد. پارامتر ظرفیت(cap) اختیاری است و به طور پیش فرض نسبت به طول(len) انجام می شود. تابع make یک آرایه ایجاد می کند و یک slice که به آرایه اشاره می کند را برمی گرداند.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    i := make([]int, 5, 5)
    fmt.Println(i)
}هنگام ایجاد یک slice، به طور پیش فرض مقادیر zero یا صفر (برای مثال برای نوع int مقدار 0) می شوند. در برنامه فوق خروجی [0 0 0 0 0] تولید خواهد شد.اضافه کردن مقدار جدید به یک sliceممکن است یک سوال برای شما پیش بیاید. اگر slice ها توسط آرایه ها پشتیبانی می شوند و آرایه ها نیز دارای طول ثابت هستند، پس چگونه یک slice دارای طول پویا است؟  خوب آنچه در اصل اتفاق می افتد این است، وقتی عناصر جدیدی به slice اضافه می شوند، یک آرایه جدید ایجاد می شود. عناصر آرایه موجود در این آرایه جدید کپی شده و رفرنس slice جدیدی برای این آرایه جدید بازگردانده می شود. ظرفیت slice جدید اکنون دو برابر slice قدیمی است. خیلی باحاله نه ؟ :) برنامه زیر همه چیز را روشن می کند.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    cars := []string{&amp;quotFerrari&amp;quot, &amp;quotHonda&amp;quot, &amp;quotFord&amp;quot}
    fmt.Println(&amp;quotcars:&amp;quot, cars, &amp;quothas old length&amp;quot, len(cars), &amp;quotand capacity&amp;quot, cap(cars)) //capacity of cars is 3
    cars = append(cars, &amp;quotToyota&amp;quot)
    fmt.Println(&amp;quotcars:&amp;quot, cars, &amp;quothas new length&amp;quot, len(cars), &amp;quotand capacity&amp;quot, cap(cars)) //capacity of cars is doubled to 6
}در برنامه فوق، ظرفیت اسلایس cars در ابتدا ۳ است. ما در خط شماره ۱۰ عنصر جدید را به cars اضافه می کنیم و slice برگردانده شده توسط append(cars, &quot;Toyota&quot;) دوباره به cars اختصاص دهید. اکنون ظرفیت cars دو برابر شده و ۶ می شود. cars: [Ferrari Honda Ford] has old length 3 and capacity 3  
cars: [Ferrari Honda Ford Toyota] has new length 4 and capacity 6پاس دادن یک اسلایس به یک فانکشن به عنوان آرگومان قبلا در مورد struct ها در این پست صحبت کردیم. اسلایس ها رو می توانیم مثل یک struct به صورت زیر در نظر بگیریم.type slice struct {  
    Length        int
    Capacity      int
    ZerothElement *byte
}یک ساختار slice شامل length، capacity و pointer به عنصر صفر آرایه است. هنگامی که یک برش به یک تابع منتقل می شود، با اینکه با مقدار (pass by value) پاس داده می شود ولی نشانگر به همان آرایه زیرین ارجاع می کند(اشاره می کند). از این رو وقتی یک اسلایس به عنوان پارامتر به یک تابع پاس داده می می شود، تغییرات ایجاد شده در داخل تابع نیز در خارج از تابع قابل مشاهده است. بیایید برنامه ای برای بررسی این موضوع بنویسیم.package main

import (  
    &amp;quotfmt&amp;quot
)

func subtactOne(numbers []int) {  
  for i := range numbers {
    numbers[i] -= 2
    }
}

func main() {  
    nos := []int{8, 7, 6}
    fmt.Println(&amp;quotslice before function call&amp;quot, nos)
    subtactOne(nos)                               //function modifies the slice
    fmt.Println(&amp;quotslice after function call&amp;quot, nos) //modifications are visible outside
}فراخوانی فانکشن در خط شماره ۱۷ برنامه فوق هر یک از عناصر اسلایس را 2 تا کم میکند. وقتی قطعه بعد از فراخوانی فانکشن چاپ می شود، این تغییرات قابل مشاهده هستند. slice before function call [8 7 6]  slice after function call [6 5 4]  برش های چند بعدیمشابه آرایه ها، اسلایس ها می توانند ابعاد مختلفی داشته باشند.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
     pls := [][]string {
            {&amp;quotC&amp;quot, &amp;quotC++&amp;quot},
            {&amp;quotJavaScript&amp;quot},
            {&amp;quotGo&amp;quot, &amp;quotRust&amp;quot},
            }
    for _, v1 := range pls {
        for _, v2 := range v1 {
            fmt.Printf(&amp;quot%s &amp;quot, v2)
        }
        fmt.Printf(&amp;quot\n&amp;quot)
    }
}خروجی برنامه فوق:C    C++  
JavaScript  
Go    Rust  بهینه سازی حافظهاسلایس ها اشاره ای به آرایه اصلی دارند. تا زمانی که اسلایس در حافظه باشد، آرایه را نمی توان garbage collect کرد. وقتی صحبت از مدیریت حافظه می شود، این مورد ممکن است نگران کننده باشد. بیایید فرض کنیم که ما یک آرایه بسیار بزرگ داریم و ما علاقه مند هستیم که فقط قسمت کوچکی از آن را پردازش کنیم. برای این کار ما یک اسلایس از آن آرایه ایجاد می کنیم و پردازش را روی اسلایس انجام می دهیم. نکته مهمی که در اینجا باید به آن اشاره شود این است که آرایه همچنان در حافظه باقی می ماند زیرا این اسلایس به آن اشاره می کند.یکی از راه های حل این مشکل استفاده از تابع copy به صورت  func copy (dst، src [] T) int برای ایحاد کپی از آن اسلایس است. به این ترتیب می توانیم از برش جدید استفاده کنیم و آرایه اصلی می تواند از حافظه حذف شود.جمله پایانی: در صورتی که مطلب را دوست داشتید لایک ❤️ کنید یا نظرتان را از طریق کامنت برای من بنویسید.</description>
                <category>انتشارات GoLang</category>
                <author>مهدی یونسی</author>
                <pubDate>Thu, 09 Sep 2021 19:24:08 +0430</pubDate>
            </item>
                    <item>
                <title>پوینترها در زبان گو</title>
                <link>https://virgool.io/golangpub/%D9%BE%D9%88%DB%8C%D9%86%D8%AA%D8%B1%D9%87%D8%A7-%D8%AF%D8%B1-%D8%B2%D8%A8%D8%A7%D9%86-%DA%AF%D9%88-zefhs3sbze0a</link>
                <description>منبع :)پوینترها یک ابزار اولیه اما خیلی قدرتمند هستند که معمولا به عنوان یک چیز سخت و مزخرف ازش یاد میشه موقع برنامه نویسی !پوینترها ساخته شدند برای تسریع و کمک به جهت جابجایی دیتا در کدها بدون اینکه نیاز باشه از یک متغیر کپی گرفته یا ساخته بشه، خوب که چی بشه دوست من !؟ جوابش سادست =&gt; مصرف کمتر مموری :)در برخی زبان ها این concept کلا دوری شده ازش، بعضی ها هم تقریبی سعی کردن مدیریتش کنند اما در زبان گو پوینترها به معنای واقعی یک ابزار خوب برای بهبود performance ازش استفاده میشه.خوب بریم سراغ این دوستمون پوینتر یک پوینتر متغیری هستش که اشاره میکنه به محل خاصی از مموری که مقداری در اونجا ذخیره شده، بنابراین شما یک متغیری را ایجاد کرده و مقداری در این قرار میدهید و خیلی ساده به جای اینکه مقدار واقعی اونو بخواین بخونین از آدرسش می تونین استفاده کنین.به کد زیر توجه کنیدpackage main

import (
   &amp;quotfmt&amp;quot
)

func main ( ) {
   myString := &amp;quota string value&amp;quot
   fmt.Println(myString)

   myInteger := 1
   fmt.Println(myInteger)
}ما دوتا متغیر ساختیم و پرینتش کردین ! هیچ کار خاصی و عجیبی هم انجام ندادیم هنوزاگر ما یک متغیری را به یک تابعی پاس بدیم، زبان میاد یک کپی از اونا میگیره و در داخل تایع ازش استفاده میکنه مثل این:func myFunction(s string){
   fmt.Println(s)
}func main() {
   myOtherString := &amp;quotanother message here&amp;quot
   myFunction(myOtherString)
}وقتیکه تابع myFunction  مقدار رشته ای s دریافت میکنه و پرینتش میکنه روی کنسول گولنک (و اکثر زبان ها) یک کپی از مقداری که ارسال شده درست میکنه در داخل تابع، وقتیکه تابع کارش به آخر میرسه اینجاست که Garbage collector میاد به سراغ این متغیر ها.خوب حالا همون کارو با پوینتر انجامش میدیمfunc myFunctionWithPointers(s *string){
   fmt.Println(s, *s)
}func main() {
   myOtherString := &amp;quotanother message here&amp;quot
   myFunctionWithPointers(&amp;myOtherString)
}خوب ایندفعه ما یکسری کارکتر جدید و عجیب داریم که اضافه شدن مثل * و &amp;در داخل () main علامت &amp; داره به زبان گو اعلام میکنه که این یک آدرسی هستش از یک متغیر، حالا گولنگ میاد میره دیتا تایپ و جایی که این مقدار در مموری قرار گرفته پیدا میکنه و نهایتا آدرس ارسال میشه به فانکشندر تابع myFunctionWithPointers علامت ستاره (*) داره به گو میگه که من دارم یک آدرس دریافت میکنم با دیتا تایپ رشته یا string. چیزی که مهمه اینکه پوینترها به تایپ نیاز دارند، پوینتر به یک عدد، پوینتر به یک رشته و یا پوینتر به یک slice و و و بعد از اینکه دیتاتایپ مشخص شد، اون در بدنه تابع ما داریم به زبان گو میگیم که s یک پوینتر است و مقداری که در اون جا ذخیره شده برای ما برمیگردهخوب حالا بریم سراغ structure type myStructure struct {
   Name string
}

func main() {
   structure := myStructure{Name: &amp;quotMyName&amp;quot}
   structureFunction(&amp;structure)
}

func structureFunction(e *myStructure){
   fmt.Println(e, *e, e.Name, (e).Name)
}اولا ما مقدار استراکچر داریم پرینت میکنیم اما با مقدار &amp; میبینیم که نشون داده میشه خوب این یعنی اینکه، یک پوینتر است به استراکچر با آن محتواوقتی که ما از ستاره استفاده میکنیم،‌ما داریم میگیم که مقدارها گرفته بشن بنابراین {MyName} که یک استراکچر فرمت شده است را دریافت میکنیموقتیکه شما دسترسی پیدا میکنی به یک فیلد از پوینتر استارکچر، گو میاد دقیقا به شما مقدار برمیگردونه. مورد آخر هم دقیقا داره همون کار انجام میده که دیگه بهش نیازی نیست و همون روش قبل کفایت میکنهحالا فرض کنین ما میخوایم متغیر آپدیت کنیم داخل تابعfunc main() {
   sliceValues := []string{&amp;quota&amp;quot,&amp;quotb&amp;quot, &amp;quotc&amp;quot}
   appendToSlice(sliceValues)
   fmt.Println(sliceValues)
}

func appendToSlice(c []string){
   fmt.Println(c)
   c = append(c, &amp;quotd&amp;quot)
}چی شده !!؟عدم استفاده از این دوستمون پوینتر نتیجش شد اینکه آپدیتی شکل نگرفت چون خارج از تابع بوده!func main() {
   sliceValues := []string{&amp;quota&amp;quot,&amp;quotb&amp;quot, &amp;quotc&amp;quot}
   appendToSliceWithPointer(&amp;sliceValues)
   fmt.Println(sliceValues)
}

func appendToSliceWithPointer(c *[]string){
   fmt.Println(*c)
   *c = append(*c, &amp;quotd&amp;quot)
}خوب بنظر ساده میاد،‌حالا چه اتفاقی می افته اگر ما maps داشته باشیم !؟func main() {
   myMap := map[string]int{
      &amp;quota&amp;quot: 1,
      &amp;quotb&amp;quot: 2,
      &amp;quotc&amp;quot: 3,
   }
   maps(myMap)
   fmt.Println(myMap)
}

func maps(c map[string]int){
   c[&amp;quotd&amp;quot] = 4
   fmt.Println(c)
}توی این مثال، تغییر در map رفتارش متفاوت بود !آپدیت شدش ! داخل فانکشن به مقدار original map !‌ مگه داریم‌!؟چرا چون که خود maps در واقع پونتر هستند و در نتیجه ما نیازی نداریم کار خاصی با map ها بکنیمیه چیز کوچولو دیگه هم هست که باید بهش توجه کرد حدس بزنین ! تابع ها هم همچنین پوینتر هستند !func main() {
   f := &amp;myFunc
}
 
func myFunc(){
 
}خوب این کار نمیکنه از اونجایی که myFunc خودش پوینتر هستش !حالا از اونجایی که پوینتر عملا یک دیتاتایپ هستش، ورودی های تابع رفتار مشابهی دارندtype myStructure struct {
   Name string
}

func (ms myStructure) noPointer(){
   ms.Name = &amp;quotxxxx&amp;quot
   fmt.Println(ms.Name)
}

func (ms *myStructure) withPointer(){
   ms.Name = &amp;quotyyyy&amp;quot
   fmt.Println(ms.Name)
}

func main() {
   theStructure := myStructure{Name: &amp;quotMyName&amp;quot}
   theStructure.noPointer()
   fmt.Println(theStructure.Name)

   theStructure.withPointer()
   fmt.Println(theStructure.Name)
}وقتیکه ورودی به عنوان یک structure استفاده میشه، مقدار تاثیری روش گذاشته نمیشه خارج از اون تابعوقتیکه ورودی مدیریت میشه به عنوان یک پوینتر، مقدار رفتارش همونی میشه که ما انتظار داریم اما اگر شما بخواین متد مستقیما صدا بزنین:func (ms myStructure) noPointer(){
   fmt.Println(&amp;quotNot a pointer&amp;quot)
}

func (ms *myStructure) withPointer(){
   fmt.Println(&amp;quota pointer&amp;quot)
}

func main() {
   myStructure{}.noPointer()
   myStructure{}.withPointer()
}دومین تابع یعنی withPointer خیلی ساده اجرا نمیشه، withPointer یک ورودی لینک شده هستش به pointer to myStructure دیتا تایپ و {} myStructure یک instance از myStructure ما میتونیم درستش کنیم با instancing structure و بعدش اضافه کردن یک پوینتر به اونtype myStructure struct {
   Name string
}

func (ms myStructure) noPointer(){
   fmt.Println(&amp;quotNot a pointer&amp;quot)
}

func (ms *myStructure) withPointer(){
   fmt.Println(&amp;quota pointer&amp;quot)
}

func main() {
   myStructure{}.noPointer()
   ms := &amp;myStructure{}
   ms.withPointer()
}خوب این تمام چیزیه که شما نیاز دارین بهش برای شروع کار با پوینتر ها :)سعی میکنم یه مقاله دیگه پیدا کنم یکم مباحث advance تری بگه. حالا برای شروع همچین بد هم نیستش :)مرسی</description>
                <category>انتشارات GoLang</category>
                <author>Farchid</author>
                <pubDate>Fri, 03 Sep 2021 23:25:15 +0430</pubDate>
            </item>
                    <item>
                <title>آهای گولنگ، مموری اضافه‌ی من کجاست؟</title>
                <link>https://virgool.io/golangpub/hey-golang-where-is-my-memory-oky2gqaxd5ly</link>
                <description>اگر تا حالا با زبان برنامه‌نویسی گولنگ کد زده باشید حتما از struct ها استفاده کردید. زمانی که یک شئ (Object) از یک struct می‌سازید با توجه به شرایط و نحوه‌ی ساخت و استفاده،‌ یک مقدار فضای مشخصی از stack یا heap اشغال می‌کنه.ولی تا حالا بررسی کردید چقدر فضا اشغال می‌کنه؟ میشه یه کاری کرد کمتر جا بگیره؟ بریم بررسی کنیم ببینیم چی میشه! اندازه‌گیری میزان اشغال حافظهخب اولین راهی که به ذهن آدم می‌رسه برای اینکه میزان اشغال حافظه یا همون مموری، توسط یه آبجکت رو اندازه بگیره، اینه که سایز هر کدوم از فیلد هاش رو باهم جمع بکنه. تو لیست زیر اندازه primitive type ها تو گولنگ رو می‌تونید ببینید.uint8, int8: 1 Byteuint16, int16: 2 Bytesuint32, int32, float32:  4 Bytesuint64, int64, float64, complex64: 8 Bytescomplex128: 16 Bytesخب با این حساب می‌تونید اندازه یک آبجکت از struct زیر رو اندازه‌گیری کنید؟type Foo struct {
   A bool
   B int64
   C bool
   D float64
}یه جمع و تفریق ساده است دیگه. طبق لیست بالا، ۱ بایت برای هر کدوم از فیلد‌های A و C و همچنین ۸ بایت برای هر فیلد B و D.جمعا میشه ۱۸ بایت.ولی من یه کوچولو شک دارم! بذارید یه کد بزنیم و ببینیم اندازه واقعی یک آبجکت از این نوع Foo چقدر حافظه اشغال می‌کنه!اندازه‌گیری اندازه‌ی آبجکت‌ها در گولنگتوی گولنگ با استفاد از پکیج unsafe میشه اندازه‌ی واقعی آبجکت‌ها رو با استفاده از تابع Sizeof فهمید.قطعه کد زیر یک آبجکت از نوع Foo میسازه و سایزش رو چاپ می‌کنه!package main

import (
   &amp;quotfmt&amp;quot
   &amp;quotunsafe&amp;quot
)

type Foo struct {
   A bool
   B int64
   C bool
   D float64
}

func main() {
   f :=  Foo{}
   fmt.Println(unsafe.Sizeof(f)) // prints 32!
}در کمال تعجب این کد عدد ۳۲ رو چاپ می‌کنه! ۳۲ کجا ۱۸ کجا! این عدد ۷۷ درصد بزرگ‌تر از چیزیه که فکر می‌کردیم!به نظر میاد گولنگ داره مموری می‌دزده!دلیلش چی می‌تونه باشه؟گولنگ و Padding/Alignmentیکم که درباره نحوه‌ی کار کامپایلر گولنگ بخونیم، می‌فهمیم مفهومی وجود داره به اسم Padding یا Alignmentکامپایلر گولنگ یه سری ویژگی‌هایی در این مورد داره. هدف اصلی این ویژگی ها هم استفاده بهتر CPU و سریع تر بودن اجرای برنامه است که دونه دونه بررسیشون می‌کنیم.۱. اندازه‌ی هر struct حداقل ۱ بایت خواهد بود.خب این که تقریبا واضحه. کامپایلر کمتر از ۱ بایت نمی‌تونه در اختیار بگیره.۲. اندازه‌ی هر struct مضرب بزرگ‌ترین فیلد آن است.توی مثال خودمون، بزرگترین فیلد B یا D هستن که هر کدوم ۸ بایت حافظه اشغال می‌کنن. یعنی اندازه‌ی Foo باید مضرب ۸ باشه. پس نتیجه می‌گیریم اندازه‌ی Foo باید بزرگ‌تر مساوی ۲۴ بایت باشه گرچه ما فقط ۱۸ بایت نیاز داریم!شاید بگید باشه همون ۲۴ بایت رو بده مشتری شیم! ولی دلایل دیگه‌ای هست که باعث میشه Foo اندازه‌اش ۳۲ بایت باشه!۳. آدرس شروع هر فیلد در حافظه، باید مضرب اندازه‌ی خودش باشه!این یعنی آدرس شروع یک فیلد از نوع int32 که ۴ بایت فضا اشغال می‌کنه باید مضرب ۴ باشه یا یک فیلد float64 باید توی آدرسی با مضرب ۸ قرار داده بشه.این‌ها همه دلایلی دارن که تو این پست بررسی نمی‌کنیم.این مورد چطوری باعث افزایش سایز میشه؟ در ادامه متوجه میشیم.۴. ترتیب قرارگیری فیلد‌ها توی حافظه، دقیقا همون ترتیبی هست که موقع تعریف struct نوشتیم.الان احتمالا بتونید حدس بزنید چرا سایز Foo شده بود ۳۲ بایت.در ادامه رفتار کامپایلر رو شرح می‌دیم.نحوه‌ی رفتار کامپایلر گولنگ برای ساخت آبجکت‌اگر فرض کنیم توی آدرس 0 بخوایم این آبجکت رو بسازیم اینطوری شروع می‌کنیم: ۱. طبق ویژگی شماره ۴، اول باید فیلد A که از نوع bool هست و ۱ بایت جا میگیره رو رزرو کنیم. از اونجایی که 0 مضرب ۱ هست (ویژگی شماره‌ی ۳) خونه‌ی 0 رو برای این فیلد در نظر میگیریم.۲. فیلد بعدی B هست که ۸ بایت جا می‌گیره. با توجه به ویژگی شماره‌ی ۳، باید آدرس شروع این فیلد مضرب ۸ باشه. پس محل این فیلد تو حافظه میشه خونه‌ی ۸ تا ۱۵. پس خونه‌ی ۱ تا ۷ چی؟ مجبوریم خالی بذاریمش! کامپایلر این محل‌های را اصطلاحا به عنوان padding خالی می‌ذاره. حالا می‌فهمیم کجا مموری دزدیده میشه!۳. فیلد C هم که ۱ بایت جا میگیره با توجه به ویژگی ها می‌ذاریمش تو خونه‌ی ۱۶.۴. برای D هم دقیقا همون اتفاقی که برای B افتاد میفته و مجبوریم بذاریمش خونه‌ی ۲۴ تا ۳۱توی تصویر زیر شکل آبجکت داخل حافظه رو می‌تونید ببینید:نحوه‌ی قرارگیری آبجکت از نوع Foo در حافظهحالا چیکار کنیم؟شاید این سوال به ذهنتون برسه که «چه کاری میشه کرد که برای مصرف کمتر حافظه؟»از ۴ تا ویژگی‌ کامپایلر گولنگ که بالاتر اشاره کردیم، فقط یک موردش رو می‌تونیم کنترل کنیم. اونم ترتیب فیلد هاست!از لحاظ ریاضیاتی ثابت میشه که اگر فیلد‌ها را به ترتیب از بزرگترین به کوچک ترین موقع تعریف struct بنویسیم، کمترین padding ممکن توسط کامپایلر قرار داده میشه.با این حال با اجرای کد زیر که نکته‌ی بالا رو رعایت کردیم عدد ۲۴ چاپ میشه.package main

import (
   &amp;quotfmt&amp;quot
   &amp;quotunsafe&amp;quot
)

type Foo struct {
   //Changed the order of fields
   B int64
   D float64
   A bool
   C bool
}

func main() {
   f :=  Foo{}
   fmt.Println(unsafe.Sizeof(f)) // prints 24
}تصویر زیر هم نحوه‌ی قرارگیری آبجکت جدید در حافظه رو نشون می‌ده:ابزار‌های کمکیلینتر‌هایی وجود دارن که struct‌ های قابل تغییر رو تشخیص می‌دن و به شما اطلاع می‌دن که بهبودشون بدید. لینک دو تا لینتر رو برای این مورد قرار می‌دم.https://gitlab.com/opennota/checkhttps://pkg.go.dev/golang.org/x/tools/go/analysis/passes/fieldalignmentنظر شخصیشخصا معتقدم که همیشه نیاز نیست این کار رو انجام بدیم و حواسمون به ترتیب فیلد‌های struct هامون باشه. از نظر من خوانایی کد در وهله اول خیلی مهم تره. در شرایط مختلف ممکنه ترتیب خاصی از فیلد‌ها خوانایی بیشتری داشته باشه. تنهای زمانی می‌ارزه فیلد‌ها را بر اساس اندازه مرتب کنیم که مموری خیلی خیلی برامون مهم باشه.منابعhttps://golang.org/ref/spec#Size_and_alignment_guaranteeshttps://go101.org/article/memory-layout.htmlhttps://dave.cheney.net/2015/10/09/padding-is-hard</description>
                <category>انتشارات GoLang</category>
                <author>میلاد ابراهیمی</author>
                <pubDate>Thu, 02 Sep 2021 18:34:17 +0430</pubDate>
            </item>
                    <item>
                <title>مفهوم Context در زبان Go</title>
                <link>https://virgool.io/golangpub/%D9%85%D9%81%D9%87%D9%88%D9%85-context-%D8%AF%D8%B1-%D8%B2%D8%A8%D8%A7%D9%86-go-jascblcr4oqq</link>
                <description>منبعدوستان من توی ترجمه Context واژی خوبی واقعا پیدا نکردم که بشه ازش استفاده کرد پس از خود همین واژه استفاده میکنم شما هم به بزرگی خودتون ببخشید :)از کانتکس ها در برنامه هایی که با گولنگ توسعه داده شده است برای مدیریت و کنترل هرچه بهتر مواردی همچون کنسل کردن، اشتراک گذاری دیتاها در برنامه نویسی اصطلاحا همروند به کار گرفته شده است.خوب این یه چیز بدیهی به نظر میرسه اما در حقیقت نه آن چنان ! یعنی چی !؟ نقطه ی شروع کانتکس ها پکیج کانتکس هستش که تقریبا خیلی پرکاربرد و میتونیم بگیم همه کاره هستش در این زبان. اگر شما هنوز با کانتکس ها سرو کله نزدید قطعا خیلی زود این اتفاق براتون می افته شایدم بهش برخوده باشین ولی توجه کافی نکرده باشید. در کل اکوسیستم زبان این پکیج یک کامپوننت کلیدی به حساب می آید بطوری که استفاده از اون خیلی گسترده هستش و پکیج های دیگه هم ازش بهره میبرند.داکیومنت این پکیج از اینجا قابل دسترس هستشContext With Valueیکی از بیشتری استفاده کانتکس ها برای Share Data هستش و یا Use Request Scoped Value. وقتیکه تعداد خیلی زیادی فانکشن دارین و میخواین دیتا بین اونها پخش یا توزیع کنید اینجا میتونید از کانتکس ها استفاده کنید. بهترین و ساده ترین روش استفاده از فانکشن context.WithValue هستش. این فانکشن یک کانتکس جدید بر اساس کانتکس والد می سازه و یک مقداری به کلید داده شده اختصاص میده.اگر بخواین بفهمین اون پشت چه خبره میشه گفت. از اونجایی که کانتکس شامل map در داخل خودش هست پس شما خیلی راحت میتونین بر اساس کلید مقدارهارو دریافت کنید.این خیلی قدرتمنده و دست شمارو باز میزاره چرا که بهتون اجازه میده که هر نوعی از دیتا داخل کانتکس ذخیره کنید. مثال ست کردن و دریافت کردن دیتا هم در زیر میتونین ملاحظه کنید.package main
import (
	&amp;quotcontext&amp;quot
	&amp;quotfmt&amp;quot
)
func main() {
	ctx := context.Background()
	ctx = addValue(ctx)
	readValue(ctx)
}
func addValue(ctx context.Context) context.Context {
	return context.WithValue(ctx, &amp;quotkey&amp;quot, &amp;quottest-value&amp;quot)
}
func readValue(ctx context.Context) {
	val := ctx.Value(&amp;quotkey&amp;quot)
	fmt.Println(val)
}چیز مهمی که پشت دیزاین این پکیج کانتکس وجود داره اینه که همه چیز یک context.Context جدید از نوع struct برمیگردونند.خوب این دیگه چیه ؟شما مجبور هستین که یادتون باشه با مقدار برگشتی باید یه کاری به هر حال انجام بدید و حتی کانتکس های قدیمی با جدیدها جایگزین کنید. این یک امر مهم در دیزاین با ثبات هستش.استفاده از این تکنیک که شما میاین با استفاده از context.Context مقداری ارسال میکنین به فانکشن های همروند. تا وقیکه مدیریت خوبی روی کانتکس ارسالی دارین خیلی روش خوبیه که scoped value ها را بین فانکشن های همروند تقسیم کنید.چی شد !؟یعنی هر کانتکس، مقدار خودش داخل اسکوپ خودش نگهداری میکنه. دقیقا کاری که پکیج net/http داره انجام میده برای هندل کردن HTTP Requests. باید مثال بزنیم تا روشن بشه چون همچنان گنگ هستش.میدلورهابهترین مثالی که میشه اینجا آورد برای این کیس میدلورهایی هستند که درخواست های ورودی هندل میکنند.تایپ http.Request شامل کانتکس هم هستش که میتونه با خودش scoped values داخل پایپلاین HTTP بیاره.این کار خیلی مرسوم هستش که یک درخواستی که بالاتر بهش گفتیم پایپلاین،‌میدلورها میان یکسری تغییرات در کد اعمال میکنند یا به عبارتی به context. و این تکنیک خیلی خوبیهpackage main
import (
	&amp;quotcontext&amp;quot
	&amp;quotlog&amp;quot
	&amp;quotnet/http&amp;quot
	&amp;quotgithub.com/google/uuid&amp;quot
	&amp;quotgithub.com/gorilla/mux&amp;quot
)
func main() {
	router := mux.NewRouter()
	router.Use(guidMiddleware)
	router.HandleFunc(&amp;quot/ishealthy&amp;quot, handleIsHealthy).Methods(http.MethodGet)
	http.ListenAndServe(&amp;quot:8080&amp;quot, router)
}
func handleIsHealthy(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	uuid := r.Context().Value(&amp;quotuuid&amp;quot)
	log.Printf(&amp;quot[%v] Returning 200 - Healthy&amp;quot, uuid)
	w.Write([]byte(&amp;quotHealthy&amp;quot))
}
func guidMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		uuid := uuid.New()
		r = r.WithContext(context.WithValue(r.Context(), &amp;quotuuid&amp;quot, uuid))
		next.ServeHTTP(w, r)
	})
}همانطور که ملاحظه میکنین میبینین که فانکشن guidMiddleware به درخواست attach شده و هر چیزی که ارسال بشه این کد بهش اعمال یا اضافه میشه.Context Cancellationفیچر خیلی خوبی که گولنگ در اختیار ما قرار ماده همین Context Cancellation هستش، خوب این دوستمون چی هست و چی کار میکنه برامون ؟دقیقا برای موقعی خوبه که شما میخواین تعداد خیلی زیادی از گوروتین هارو بهشون بگین کنسل بشن. برای مثال فرض کنین یک فانکشن دارین که ده ها گوروتین استارت میکنه. اون فانکشن اصلی صبر میکنه تا تمام گوروتین ها کارشون تموم بشه و یا یک سیگنال کنسل ایجاد بشه قبل از اینکه بقیه پروسه ادامه پیدا کنه.اگر سیگنا کنسل دریافت بشه ما میخوایم اینو پخشش کنیم به همه ی گوروتین هاخوب که چی بشه !؟شما دیگه منابع کامپیوتر هدر ندادین اگر یک کانتکس مشترک بین همه گوروتین های خودتون تقسیم کرده باشین.خیلی ساده برای ایجاد یک کانتکس با ویژگی کنسل شدن فقط کافیه (ctx)context.WithCancel صدا زده بشه و کانتکس به عنوان ورودی پاس داده بشه.مثال عملیش میشه اینکه مثلا ما داریم یه درخواستی به یک وب سرویسی می زنیم و اگر جوابی برای ما برنگرده در طی اون زمانی که مشخص کردیم وقتی که response برمیگرده تمام درخواست ها را کنسل میکنیم.package main
import (
	&amp;quotcontext&amp;quot
	&amp;quotfmt&amp;quot
	&amp;quotio/ioutil&amp;quot
	&amp;quotnet/http&amp;quot
	neturl &amp;quotnet/url&amp;quot
	&amp;quottime&amp;quot
)

func queryWithHedgedRequestsWithContext(urls []string) string {
	ch := make(chan string, len(urls))
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	for _, url := range urls {
		go func(u string, c chan string) {
			c &lt;- executeQueryWithContext(u, ctx)
		}(url, ch)

		select {
		case r := &lt;-ch:
			cancel()
			return r
		case &lt;-time.After(21 * time.Millisecond):
		}
	}
	return &lt;-ch
}

func executeQueryWithContext(url string, ctx context.Context) string {
	start := time.Now()
	parsedURL, _ := neturl.Parse(url)
	req := &amp;http.Request{URL: parsedURL}
	req = req.WithContext(ctx)

	response, err := http.DefaultClient.Do(req)

	if err != nil {
		fmt.Println(err.Error())
		return err.Error()
	}

	defer response.Body.Close()
	body, _ := ioutil.ReadAll(response.Body)
	fmt.Printf(&amp;quotRequest time: %d ms from url%s\n&amp;quot, 
        time.Since(start).Nanoseconds()/time.Millisecond.Nanoseconds(), url)
	return fmt.Sprintf(&amp;quot%s from %s&amp;quot, body, url)
}هر درخواست در یک گوروتین جداگانه اجرا میشود، کانتکس به تمامی درخواست هایی که زده شده اند فرستاده میشود. تنها چیزی که با کانتکس انجام شده اینه که اون ارسال شده به HTTP client. این اجازه میده تا پروسه کنسل شدن خیلی راحت صدا زده بشه و کانکشن برقرار باشه.Context Timeoutاین پترن خیلی مرسوم هستش برای ارسال درخواست خای خارجی مثل کوعری های دیتابیس یا گرفتن دیتا از یک سرویس دیگر چه از طریق HTTP و یا gRPC. مدیریت این سناریوها با استفاده از این پکیج خیلی راحت انجام میشه. تنها کاری که لازم دارین انجان بدین صدا زدن فانکشن context.WithTimeout(ctx, time) در واقع کانتکس و زمان باید پاس داده بشه.ctx, cancel := context.WithTimeout(context.Background(), 100 * time.Millisecond)با این کار شما فانکشن کنسل دریافت میکنید برای موقعی که بخواین صداش کنین. دقیقا مثل Context Cancellation قبلی کار میکنه</description>
                <category>انتشارات GoLang</category>
                <author>Farchid</author>
                <pubDate>Sun, 15 Aug 2021 20:46:31 +0430</pubDate>
            </item>
                    <item>
                <title>پیاده سازی Mutex در گولنگ</title>
                <link>https://virgool.io/golangpub/%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-mutex-%D8%AF%D8%B1-%DA%AF%D9%88%D9%84%D9%86%DA%AF-pftu6iymqqon</link>
                <description>منبع :)خوب اینجا ما یاد میگیریم چطوری مشکل Race Condition با استفاده از موتکس ها و کانال ها حل کنیم.اول از همه race condition چه کوفتی هست اصلا !؟این مشکل وقتی به وجود میاد که ۲ یا چندین ترد میخواد دسترسی پیدا کنند به دیتاهای توزیع شده و سعی کنند اونارو عوض کنند. خوب نمیشه که فقط یکی میتونه بیاد و یک مقداری تغییر بده اینجاست که conflict شروع میشه.خیلی ساده وقتی یک برنامه وقتی بصورت concurrent داره اجرا میشه. نباید منابع قابل دسترس باشه برای چندین Goroutine.گوروتین چیه !؟گوروتین ها فانکشن ها یا متد هایی هستند که بصورت همزمان با بقیه فانکشن ها و متد ها اجرا میشن. در مقایسه با تردها گوروتین ها بسیار سبک تر و به قولی کم هزینه تر هستند.خوب مثال خیلی ساده ای اینجا شروع میکنیم. فرض کنیم یه کدی داریم که داره مقدار x یک واحد بهش اضافه میکنه و داخل خود x جایگذاری میکنه.x = x + 1تا وقتیکه این کد توسط یک گوروتین قابل دسترس هستش نباید هیچ مشکلی باشه. بیایم بررسی کنیم چرا این کد به مشکل بر میخوره وقتیکه ما چندین گوروتین داریم که دارند بصورت همزمان اجرا میشن. برای اینکه خیلی پیچیده نشده موضوع فرض کنیم ۲ تا گوروتین داریم که دارن کد بالارو همزمان اجرا میکنند.طی ۳ مرحله این کد داره داخل سیستم اجرا میشه مقدار ا فعلی x گرفته میشهمقدار x + 1 محاسبه میشهمقدار محاسبه شده assign میشه به خود xوقتی همه این ۳ مرحله توسط یک گوروتین انجام میشه همه چیز اوکیه و مشکلی نیست.بیاین بررسی کنیم ببینیم چه اتفاقی می افته وقتی ۲ تا گوروتین این کد اجرا میکنن بصورت همزمان. تصویر پایین کاملا نشون میده چه اتفاقی می افته وقتی ۲ تا گوروتین دسترسی پیدا میکنند به x = x +1 بصورت همزمان.ما مقدار اولیه ایکس صفر درنظر گرفتیم. گوروتین ۱ مقدار ایکس میگیره و با ۱ جمعش میکنه و قبل از اینکه بخواد مقدار محاسبه شده به خود ایکس assign کنه گوروتین دوم میاد و مقدار اولیه ایکس که هنوز صفر هستش میگیره و x+1 محاسبه میکنه دوباره سیستم میاد و از موقعیت قبلی گوروتین ۱ شروع میکنه به اجرا شدن و مقدار محاسبه می ریزه داخل ایکس و میشه ۱. حالا گوروتین دوم میاد از ادامه ی مسیر خودش شروع میکنه به اجرا شدن و نهایتا مقدار ایکس بازهم میشه ۱ بعد از اینکه هر دو گوروتین اجرا شدن.حالا یه سناریوی متفاوت بررسی کنیم.همونطور که ملاحظه میکنین گوروتین اول ۳ مرحلرو کامل اجرا میکنه و مقدار ایکس میشه ۱ بعدش گوروتین دوم شروع به اجرا شدن میکنه و بعد از ۳ مرحله مقدار ایکس به ۲ تغییر پیدا میکنه.خوب از این دو سناریو شما فهمیدین که مقدار نهایی ایکس یا ۱ هستش و یا ۲بستگی به نوع Context switching داره، خوب یعنی چی !؟ یعنی اصلا ضمانتی وجود ندارد که ترتیب اجرای اینم گوروتین ها چطوری باشه و اینجاست که ما به Race Condition بر میخوریم :)فقط در یک صورت در سناریو بالا Race Condition میتونه جلوش گرفته بشه اونم وقتیکه یک گوروتین بهش اجازه داده میشه دسترسی داشته باشه به Critical section کد در یک زمان معین. این کار شدنیه با استفاده از موتکس (Mutex)Mutexموتکس مکانیزم قفل کردن برای ما فراهم میکنه و تضمین میکنه که فقط یک گوروتین اجرا کنه کد و از Race Condition جلوگیری خواهد شد.در زبان گو Mutex در پکیج Sync قابل دسترس هستش. دو متد تعریف شده در mutext تحت عنوان Lock و Unlock هر کدی که بین این دو متد اجرا میشه،‌فقط توسط یک گوروتین داره مدیریت میشه بنابراین دیگه Race Condition معنی پیدا نمیکنهmutext.Lock()
x = x + 1
mutex.Unlockاگر یک گوروتین قفل شده باشه و یک گوروتین دیگه بخواد  تلاش کنه برای قفل شدن اتفاقی که می افته اینه که بلاک میشه تا زمانیکه موتکس به حالت unlock دربیاد اون وقت اجازه پیدا میکنه که کارشو انجام بده.برنامه ای با Race Conditionتوی این بخش ما برنامه ای مینویسیم که مشکل Race Condition داره و توی بخش پایین تر راه حل ها رو مطرح میکنیم :)package main 
import (  
    &amp;quotfmt&amp;quot
    &amp;quotsync&amp;quot
    )
var x  = 0  
func increment(wg *sync.WaitGroup) {  
    x = x + 1
    wg.Done()
}
func main() {  
    var w sync.WaitGroup
    for i := 0; i &lt; 1000; i++ {
        w.Add(1)        
        go increment(&amp;w)
    }
    w.Wait()
    fmt.Println(&amp;quotfinal value of x&amp;quot, x)
}در برنامه بالا فانکشن increment مقدار x یک واحد اضافه میکنه و بعدش ()Done صدا میکنه از WaitGroup برای اینکه بگه کارش تموم شده.ما تعداد ۱۰۰۰ تا گوروتین ایجاد کردیم، هر گوروتین بصورت همزمان اجرا میشه و race condition وقتی بوجود میاد که سعی میکنه مقدار ایکس افزایش بده. تعداد زیادی گوروتین دارن تلاش میکنن که به مقدار ایکس دسترسی پیدا کنن !اگر چندین و چند بار شما این برنامه روی سیستم خودتون اجراش کنین هر بار ممکنه یه عددی نمایش بده مثلا941 یا 928 یا 922  و و وحل مشکل با استفاده از موتکس ما اومدین ۱۰۰۰ تا گوروتین ساختیم و اگر هر کدومشون ۱ واحد به ایکس اضافه کنن مقدار نهایی ایکس باید ۱۰۰۰ بشهpackage main  
import (  
    &amp;quotfmt&amp;quot
    &amp;quotsync&amp;quot
    )
var x  = 0  
func increment(wg *sync.WaitGroup, m *sync.Mutex) {  
    m.Lock()
    x = x + 1
    m.Unlock()
    wg.Done()   
}
func main() {  
    var w sync.WaitGroup
    var m sync.Mutex
    for i := 0; i &lt; 1000; i++ {
        w.Add(1)        
        go increment(&amp;w, &amp;m)
    }
    w.Wait()
    fmt.Println(&amp;quotfinal value of x&amp;quot, x)
}میتونین کد اینجا هم اجرا کنینتایپ Mutext از نوع Struct هستش و ما اومدیم متغیر m که صفر هم هستش و از تایپ mutex هست ساختیم و همونطور که میبینین مقدار ایکس که داره تغییر بین فانکشن های Lock و Unlock قرار گرفته و از race condition جلوگیری میشه بخاطر اینکه فقط یک گوروتین اجازه اجرای این کدرو داره در آن واحد.مقدار نهایی الان ۱۰۰۰ خواهد بودیه نکته هست که خیلی مهمه اونم اینه که اینجا go increment(&amp;w, &amp;m) حتما آدرس موتکس باید پاس داده بشه اگر موتکس مقدار پاس داده بشه بجای آدرسش. هر گوروتین یک کپی از موتکس خواهد داشت و race condition لعنتی همچنان پابرجاست.حل مشکل Race Condition با استفاده از کانال هابا استفاده از کانال ها هم ما میتونیم مشکل Race Condition حل کنیم.package main  
import (  
    &amp;quotfmt&amp;quot
    &amp;quotsync&amp;quot
    )
var x  = 0  
func increment(wg *sync.WaitGroup, ch chan bool) {  
    ch &lt;- true
    x = x + 1
    &lt;- ch
    wg.Done()   
}
func main() {  
    var w sync.WaitGroup
    ch := make(chan bool, 1)
    for i := 0; i &lt; 1000; i++ {
        w.Add(1)        
        go increment(&amp;w, ch)
    }
    w.Wait()
    fmt.Println(&amp;quotfinal value of x&amp;quot, x)
}کد میتونین اینجا هم اجراش کنینتوی برنامه بالا ما اومده یک Buffered Channel ساختیم با ظرفیت ۱  و اون کانال به فانکشن increment هم پاس داده شده همونطور که میبینین.این آقای buffered channel استفاده شده تا مطمئن باشیم که فقط یک گوروتین دسترسی به افزایش x داره. و این داره هندل با ارسال مقدار true به کانال و بعد از افزایش ایکس مقدار کانال خونده میشه. خوب طی این مرحله چه اتفاقی می افته ؟ تمامی گوروتین هایی که دارن سعی میکنن توی این کانال بنویسن بلاک میشن تا زمانیکه این مقدار از کانال خونده بشه. جالبه نه !؟ باز هم اینجا فقط به یک گوروتین اجازه داده شد که این عملیات انجام بده و Race Condition هندل شد و مقدار نهایی ۱۰۰۰ میشه.تفاوت بین Mutex و Channelsما مشکل Race Condition با استفاده از این دو بزرگوار حل کردیم ! حالا چطوری تصمیم بگیریم از کدوم کجا استفاده کنیم ؟جواب سوال اینه بستگی داره چه مشکلی شما میخواین حل کنین. اگر مشکل شما بیشتر فکر میکنید با موتکس حل میشه خوب برین اجراش کنین و یا برعکس اگر فکر میکنین با کانال قابل حل شدن شک نکنید.اکثر افرادی که تازه کار هستن در گولنگ مشکلات Concurrency اکثرا با کانال ها برطرف میکنن که خیلی فیچر خفن و باحالیه که این زبان در اختیار ما گذاشته. اما این زبان آپشن های دیگه ای هم مثل موتکس در اختیار ما گذاشته در هر صورت استفاده از هر کدوم هیچ مشکلی بوجود نمیاره.در حالت عادی کانال ها استفاده میشن موقعیکه گوروتین ها نیازمند این هستند که در ارتباط با یکدیگر باشند و موتکس برای موقعی که یک گوروتین فقط باید دسترسی داشته باشه به یک بخش critical کد.در مشکلی که ما حل کردیم موتکس بهترین انتخاب چرا چون هیچ نیازی به ارتباط بین گوروتین ها نبوده.پیشنهاد ما اینه که یک ابزار برای مشکلتون انتخاب کنین و به هیچ وجه سعی نکنین مشکل فیت کنید برای یک ابزار !</description>
                <category>انتشارات GoLang</category>
                <author>Farchid</author>
                <pubDate>Wed, 11 Aug 2021 00:36:04 +0430</pubDate>
            </item>
                    <item>
                <title>همروندی در زبان گو</title>
                <link>https://virgool.io/golangpub/%D9%87%D9%85%D8%B1%D9%88%D9%86%D8%AF%DB%8C-%D8%AF%D8%B1-%D8%B2%D8%A8%D8%A7%D9%86-%DA%AF%D9%88-td5v9appdshx</link>
                <description>در این مقاله میخوایم در مورد همروندی صحبت کنیم، هر جا از این واژه استفاده شده منظور همان Concurrency است.همروندی در زبان گولنگ یکی از مهمترین ویژگی های این زبان به حساب می آید، اما همروندی در این زبان یک راه تفکر است بیشتر تا یک Syntax.برای اینکه به قدرت زبان گو پی ببرید لازم است اول شما روش این زبان را برای کدهایی که بصورت همزمان اجرا میشوند را بررسی کنید.مدلی که زبان گو از آن در همروندی استفاده میکند CSP نام دارد که مخفف Communicating sequential proccesses یا به عبارتی ارتباط متوالی فرآیندها با یکدیگر که در علم پایه کامپیوتر به این مدل ارتباط بین سیستم های همروند میگویند.اما ما اینجا نیستیم که در مورد علم و دانش صحبت کنیم که !!! بنابراین میریم سراغ موارد عملی و جذاب.یه جمله ی معروفی هستش که میگه :Do not communicate by sharing memory; instead, share memory by communicatingخوب این واقعا یعنی چی؟ برای خود من مدت های زیادی طول کشید تا اینو کامل درکش کنم ولی وقتی درکش کردم کارکردن با گولنگ برام خیلی خیلی روان تر شد. آلبرت انیشتن میگه اگر شما نمیتونید خیلی ساده توضیح بدین چیزیرو، شما اونو خیلی خوب متوجه نشدینش! بنابراین تعریف ساده تر اون جمله میشه:Do not communicate by sharing memoryبه عنوان یک برنامه نویس وقتی در مورد همروندی فکر میکنید و نحوه ی اجرای کد اون، بیشترین چیزی که به ذهنتون میرسه تعداد خیلی زیادی از thread هستش که بصورت همزمان دارن بصورت خیلی پیچیده اجرا میشن.بنابراین اکثر مواقع ناچار به اشتراک گذاری دیتا هستین مثل structures, variable, memory و هر چیزی که فکرشو میکنین به thread های مختلف.شما اینکارو انجام میدین با قفل کردن بخشی از مموری که 2 threads نمیتونن همزمان یا بنویسن و یا دسترسی داشته باشند و یا اینکه به امان خدا ولش میکنین تا آزاد بشه و بهترین حالت شاید پیش بیاد و این همون مشکلیه که خیلی از زبانی محبوب باهاش درگیر هستند و باعث اتفاق های عجیبی مثل race condition, memory mangement و اتفاقات غیرقابل پیش بینی که هر شب ممکنه شمارو از خواب بیدار کنه.Instead, share memory by communicatingخوب گو چطوری این کارو انجام میده ؟بجای قفل کردن متغیرها برای اشتراک گذاری مموری، گو به شما این اجازه میده که متغیری را از یک thread به یک thread دیگر ارسال کنید (در حقیقت دقیقا یک thread نیست اما فعلا بیایم اونو یک thread درنظر بگیریم)رفتارپیش فرض برای thread ارسال کننده و همچنین thread دریافت کننده اینه که هر دو صبر میکنند تا value ارسال شده به مقصدش برسه. نکته اینجاست که در زمانی که این دو thread صبر کرده اند باعث میشه یک همگام سازی مناسبی بین thread ها بوجود بیاد.چه مزیتی به ما میده این موضوع؟در واقع شانس خیلی خیلی کمتری وجود داره که مواردی مثل race conditions بخواد پیش بیاد چون هر دو صبر میکنند تا value کاملا ارسال بشه.گولنگ این امکانات بصورت Native و built-in به شما ارایه میکند بدون نصب هیچگونه فریمورک و یا کتابخانه ای خاص.گولنگ همچنین به شما ویژگی دیگه ای هم میده تحت عنوان buffered channel که در بعضی موارد شما نمیخواینهر دو thread قفل و سینک بشن تا زمانی که value ارسال بشه. و فقط زمانی locking اتفاق بی افته که شما تعداد خاصی تعریف کرده باشین برای صبر کردن این thread هانوشتن کد همروند در گولنگخوب چطوری ما میخوایم با روش share by communication model کد خودمونو بنویسیم ؟در گو، یک گو روتین (Goroutine) با خودش این مفهومی که ما دنبالش میگردیمو برای ما میاره !درواقع، اون یک thread نیست، اون یک function هستش که میتونه بصورت همروند با بقیه گوروتین ها در یک فضای مشترک اجرا بشه. تعداد اون ها زیاده در لایه OS و اگر یکی از اون ها قفل بشه بقیه به کار خودشون ادامه میدن. تمام این مراحل سینک کردن و مدیریت مموری در خود زبان داره مدیریت میشه بصورت Native. اینکه میگیم اون ها thread نیستن چون لزوما بصورت پارالل اجرا نمیشنبرای استارت یک گو روتین کافیه از کلمه ی کلیدی &quot;go&quot; استفاده کنین.خط بالا یک گوروتین را که فانکشن ()start اجرا میکنهوجود داره. برنامه اول چاپ میکنه started توجه کنید که خطی که ما چاپ کردیم started بعد از جایی که گوروتین اجرا شده این به ما این نکته نشون میده که بعد از اینکه گوروتین استارت شده برنامه اجراش به خط بعدی رفته. ما یک تایم اوت ست کردیم برای گو روتین خودمون و بعد از رسیدن به اون تایم میبینیم که اجرا میشه و نهایتا finished چاپ میشهحالا چه اتفاقی می افته اگر ما تایم اوت حذف کنیم ؟ اصلا چاپ نشد ! چرا ؟به دلیل اینکه گوروتین اصلی اجراش تموم میشه تا بخواد اون یکی برای خودش برنامه ریزی بکنه.                                             Main Goroutineفانکشن main در پکیج main یک گوروتین اصلی هستش. تمای گوروتین ها شروع میشن از همین main goroutine این گوروتین ها میتوانند چندین گوروتین دیگر را استارت بزنند.گوروتین اصلی بیانگر برنامه اصلی است. وقتی خارج میشه یعنی کل اپلیکیشن خارج شده.گوروتین ها والد و یا فرزندی ندارند. وقتی شما یک گوروتین را استارت میزنید اون کنار بقیه گوروتین ها اجرا میشه.هر گوروتین زمانی تمام میشود که فانکشن اون چیزی را برگرداند. تنها مورد استثنا اینه که تمامی گوروتین ها استاپ میشوند وقتیکه گوروتین اصلی استاپ یا خارج شود.                                   Creating Multiple Goroutinesبرنامه بالا در یک لوپ ۱۰ گوروتین را اجرا میکند و هروقتیکه شما این برنامه را اجرا کنید به شما نتیجه ای مختلف میدهد از اونجایی که گوروتین ها بصورت همروند دارند اجرا میشوند نتیجه قابل انتظاری نمیشود دید.</description>
                <category>انتشارات GoLang</category>
                <author>Farchid</author>
                <pubDate>Mon, 09 Aug 2021 18:53:50 +0430</pubDate>
            </item>
                    <item>
                <title>پوینتر ها در گو |‌ آشنایی و درک بهتر آنها</title>
                <link>https://virgool.io/golangpub/%D9%BE%D9%88%DB%8C%D9%86%D8%AA%D8%B1-%D9%87%D8%A7-%D8%AF%D8%B1-%DA%AF%D9%88-%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D9%88-%D8%AF%D8%B1%DA%A9-%D8%A8%D9%87%D8%AA%D8%B1-%D8%A2%D9%86%D9%87%D8%A7-ja8q9uwzezin</link>
                <description>اگر قلق و پشت صحنه پوینترها  رو ندونیم به احتمال زیاد توی پیاده سازی هامون دردسر های زیادی خواهیم داشت و خیلی جاها بدون اینکه متوجه باشیم چطور کدمون کار میکنه (یا بدتر با آزمون و خطای چند حالت و رسیدن به حالتی که کار میکنه!) کد میزنیم و بعدا میتونه دردسر داشته باشه برامون.پوینتر ها در گولنگ چی هستن؟قبل از همه یک تعریف انگلیسی در موردش بخونیم:Pointers in Go programming language is a variable which is used to store the memory address of another variable.این تعریف داره میگه پوینترها در گو متغیرهایی هستند که آدرس مموری یک متغیر دیگه رو توی خودشون نگه میدارند. این تعریف یک نکته مهم داره. پوینتر ها یک متغیر هستند. یعنی پوینتر ها چیز خیلی پیچیده ایی نیستند، یک متغیر هستند که جای مثلا استرینگ و اینتیجر توی خودشون آدرس نگه میدارند. خود پوینترها توی مموری مثل بقیه متغیرها یک آدرس دارن و میتونیم با de-reference کردن یک پوینتر به متغیری که به اون اشاره میکنه دسترسی داشته باشیم. بیاید یک مثال بزنیم، یک تایپ تغریف کردم که جلوتر باهاش کلی کار داریم:type T struct {
   Name string
}برای مثال میتونیم به روش زیر از این تایپ یک پوینتر بسازیم:p := &amp;T{
   Name: &amp;quotMohammad&amp;quot,
}علامت &amp; داره میگه که به من مقدار متغیری که ساختم رو برنگردون، در عوض آدرسش توی مموری رو برگردون. پس ما یک پوینتر داریم به اسم P که value اون آدرس یک متغیر توی مموری هست.fmt.Printf(&amp;quotp is pointing to: %p \n&amp;quot, p)       // 0xc00010a040با استفاده از %p هم میتونیم یک آدرس رو نمایش بدیم. همونطوری که می‌بینید توی کد بالا آدرسی که p داره بهش اشاره میکنه رو مشاهده میکنیم. اما همونطوری که گفتم خود پوینترها هم یک نوع متغیر هستند و توی مموری یک آدرس دارن. چطور به اون ها دسترسی داشته باشیم؟fmt.Printf(&amp;quotp address: %p \n&amp;quot, &amp;p)       // 0xc000128018این کد خود آدرس p رو برمیگردونه. همونطوری که میبینید یک آدرس کاملا متفاوت از آدرس متغیر قبلی داریم. حالا اگر بخوایم از یک پوینتر یک کپی بسازیم چه اتفاقی میوفته؟newP := p
fmt.Printf(&amp;quotnewP is pointing to: %p \n&amp;quot, newP) // 0xc00010a040
fmt.Printf(&amp;quotnewP address: %p \n&amp;quot, &amp;newP) // 0xc000128028همونطوری که توی کدبالا می‌بینید آدرسی که متغیر جدیدمون بهش اشاره میکنه با آدرس متغیر قبلی یکسانه. اما چون یک متغیر جدید ساختیم آدرس خود پوینتر با آدرس های قبلی فرق داره.وقتی یک تابع پوینتر میگیره چنین اتفاقی میوفته. ما آدرس رو داریم میفرستیم و باید تغییراتی که میخوایم رو روی اون آدرس تغییر بدیم. یعنی روی value ورودی تابعمون نه روی آدرس متغیری که به عنوان ورودی تعریف کردیم.چطور پوینتر بسازیم؟با سه روش زیر شما یک متغیر پوینتر میسازید:var p1 *T
p2 := new(T)
p3 := &amp;T{}روش دوم و سوم تقریبا یک کار هستند. داره میگه اول یک متغیر توی حافظه بساز، حالا آدرسش رو بریز توی پوینتری که ما گفتیم. اما روش اول صرفا میگه یک پوینتر بساز. بیاید ببینیم این پوینترها به چه آدرسی توی حافظه اشاره میکنند:fmt.Printf(&amp;quotp1 address: %p\n&amp;quot, p1) // 0X0
fmt.Printf(&amp;quotp2 address: %p\n&amp;quot, p2) // 0xc000010200
fmt.Printf(&amp;quotp3 address: %p\n&amp;quot, p3) // 0xc000010210نکته مهمی که باید توجه کنیم آدرسیه که p1 داره بهش اشاره میکنه. به p1 میگیم nil pointer، یعنی یک پوینتر که به متغیر خاصی توی حافظه اشاره نمیکنه و خالیه. چرا باید حواسمون بهش باشه؟ما راحت میتونیم متغیر های p2 و p3 رو با استفاده از *p دی رفرنس کنیم و به مقداری که بهش اشاره میکنن دسترسی داشته باشیم. اما گفتیم p1 به هیچی اشاره نمیکنه، اگه dereference اش کنیم چه اتفاقی میوفته؟panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x49a812]پنیک میکنیم و کرش میکنیم! همیشه باید مراقب این nil pointer ها باشیم و قبل از دی رفرنس کردن یک پوینتر نیل بودنش رو چک کنیم.کار با اسلایس و پوینتر‌هااسلایس چیه؟ یک پوینتر به یک آرایه هست که علاوه بر امکانات آرایه یک شعوری داره که باعث میشه اگر داشتیم از ظرفیت آرایه بیشتر میشدیم یک آرایه جدید میسازه و مقادیر قبلی رو اونجا کپی میکنه و پوینترش دیگه به آرایه جدید اشاره میکنه.برای ساختن یک اسلایس از پوینترها میتونیم از این روش ها استفاده کنیم:var a1 []*T
a2 := make([]*T, 10)
a3 := []*T{
   {Name: &amp;quot&amp;quot},
}خب خب رسیدیم جای جالب. همونطوری که گفتیم اسلایس در اصل یک پوینتر هست. پس اما پوینتر a1 به کجا اشاره میکنه؟ برعکس a2 و a3 که یک آرایه براشون ساخته شده به هیچ جا اشاره نمیکنه:fmt.Printf(&amp;quota1 address: %p\n&amp;quot, a1) // 0x0
fmt.Printf(&amp;quota2 address: %p\n&amp;quot, a2) // 0xc000066050
fmt.Printf(&amp;quota3 address: %p\n&amp;quot, a3) // 0xc00000e028اما بازم باید مراقب باشیم! چرا؟ چون توی a2 ما گفتیم یک آرایه از پوینترها برامون بساز. برامون پوینتر رو میسازه ولی پوینترها nil هستد! fmt.Println(a2) // [&lt;nil&gt; &lt;nil&gt; &lt;nil&gt; &lt;nil&gt; &lt;nil&gt; &lt;nil&gt; &lt;nil&gt; &lt;nil&gt; &lt;nil&gt; &lt;nil&gt;]
fmt.Printf(&amp;quota2[0] address: %p\n&amp;quot, a2[0]) // a2[0] address: 0x0خب این چطور میتونه خطرناک باشه؟ برای مثال توی a3 ما گفتیم یک آرایه از پوینتر ها بساز ولی برای تک تک پوینتر ها داریم میگیم به کجا اشاره کن و nil نیستند.func C4() {
   a1 := []*T{
      {Name: &amp;quot&amp;quot},
   }
   ChangeItem(a1[0])
   fmt.Println(&amp;quotName is&amp;quot, a1[0].Name) // Name is Mohammad
}
func ChangeItem(t *T) {
   *t = T{Name: &amp;quotMohammad&amp;quot}
}اگر این مثال رو اجرا کنیم چون a1[0] ما پوینتری هست که به جایی توی حافظه اشاره میکه و ما داریم اون آدرس رو به تابع میدیم و آدرس توی t هست و با دی رفرنس کردن t به اون متغیر توی حافظه دسترسی داریم. پس میتونیم مقدارش رو تغییر بدیم.func C5() {
   a1 := make([]*T, 10)
   ChangeItem(a1[0]) // panic !!
   fmt.Println(&amp;quotName is&amp;quot, a1[0].Name)
}اما اگر این کد رو اجرا کنیم panic میکنیم. علت اینه ما داریم آدرس 0x0 رو به عنوان ورودی به تابع میدیم و آدرسی که t بهش اشاره میکنه 0x0 هست، پس ما نمیتونیم این پوینتر رو دی-رفرنس کنیم در نتیجه پنیک میخوریم.a1 := make([]*T, 10)
a1[0] = &amp;T{}
ChangeItem(a1[0])
fmt.Println(&amp;quotName is&amp;quot, a1[0].Name) // Name is Mohammadبرای حل این مشکل ما میتونیم قبل صدا زدن تابع یک آدرس توی حافظه به پوینتر بدیم و انتظار داشته باشیم اون آدرس تغییر کنه.البته با این تریک هم میشه یک پوینتر نیل رو مقدار دهی کنیم که من خیلی ازش خوشم نمیاد چون علاوه بر پیچیده کردن و سخت شدن کد امکان بوجود اومدن خطاهای دیگه ایی رو به کد بیس ما اضافه میکنه.ما میتونیم جای اینکه پوینتر نیل رو بخوایم مقدار دهی کنیم میتونیم آدرس اون پوینتر رو به عنوان پوینترِ یک پوینتر به تابع بدیم و از طریق این پوینترِ پوینتر به خود پوینتر دسترسی داشته باشیم و بگیم که به کجا اشاره کنه.func main() {
   var p *T
   ChangeName(&amp;p)
   fmt.Println(p.Name)
}
func ChangeName(t **T) {
   *t = &amp;T{
      Name: &amp;quotHello&amp;quot,
   }
}</description>
                <category>انتشارات GoLang</category>
                <author>محمد حسینی راد</author>
                <pubDate>Thu, 15 Jul 2021 13:40:34 +0430</pubDate>
            </item>
                    <item>
                <title>گولنگ: چرا باید گولنگ را در 1400 یاد بگیرید.</title>
                <link>https://virgool.io/golangpub/%DA%AF%D9%88%D9%84%D9%86%DA%AF-%DA%86%D8%B1%D8%A7-%D8%A8%D8%A7%DB%8C%D8%AF-%DA%AF%D9%88%D9%84%D9%86%DA%AF-%D8%B1%D8%A7-%D8%AF%D8%B1-1400-%DB%8C%D8%A7%D8%AF-%D8%A8%DA%AF%DB%8C%D8%B1%DB%8C%D8%AF-foq7ylithmje</link>
                <description>گولنگ زبان نسبتا جوان اما محبوب بین برنامه نویسان است. بنابر نظرسنجی سایت StackOverflow، گولنگ سومین زبانی است که توسعه دهندگان علاقه به مطالعه دارند.در این مقاله، سعی خواهیم کرد دلایل محبوبیت گو را بیان کنیم و همچنین ببینیم در چه جاهایی از این زبان استفاده می شود و چرا ارزش یادگرفتن دارد. اگر شما تازه وارد دنیای برنامه نویسی شده‌اید می توانید گولنگ را به عنوان اولین زبان برنامه‌نویسی‌یتان یاد بگیرید.خلاصه ای از تاریخچه گوگولنگ در شرکت گوگل مفهوم‌سازی و طراحی شد و اسمش را هم از دو حرف اول نام این شرکت (گوگول) گرفته است. این زبان توسط Robert Griesemer، Rob Pike (یکی از خالقان UTF8)، وKen Thompson  افسانه‌ای، خالق Unix و زبان B (جد C)، طراحی و بنا گذاشته شد.گولنگ شباهت‌هایی به زبان C، و مانند C، دارد و یک ابزار برای برنامه‌نویسان حرفه‌ای است. با گو، بیشترین اثر و نتیجه را با کمترین تلاش بدست می آورید. بنابراین، این زبان بسیار فراتر از یک نسخه بروزشده زبان C است. گو در اصل جایگزینی برای ++C بود چرا که ++C زبانی بسیار عریض‌وطویل و دشوار است بخصوص فهمیدن آخرین استانداردهای آن. در مقایسه با ++C، گو زبانی راحت‌تر و آسان‌تر برای یادگیری است.گو از ایده های خوب زبان‌های مختلف برنامه‌نویسی استفاده و اقتباس می کند، این در حالی است که از ویژگی‌هایی که منجر به پیچیدگی، نامطمئنی و ناپایداری کد می شود تا حدی دوری می‌کند. ابزارهای گو نیز برای مسئله همروندی جدید است و به منظور بهره‌وری بیشتر است.گولنگ بخصوص مناسب برای توسعه زیرساخت، مانند سرورهای شبکه، و همچنین ابزارها و سیستم‌ها برای برنامه‌نویسان است. بااین‌حال این زبان برنامه نویسی یک زبان هم منظوره است و در حوزه‌هایی مانند گرافیک، اپلیکیشن‌های موبایل، و یادگیری ماشین استفاده می‌شود.گولنگ به شما این توانایی را می دهد تا یک پروژه را سریع، راحت و قابل استفاده در شکل میکروسرویس پیاده‌‎سازی کنید. این یک مزیت برای شرکت‌هایی است که می خواهند محصولات تخصصی خود را در سرویس‌های کوچک تولید کنند. در این مورد دیگر توجیه ندارد از فریم‌ورک‌هایی استفاده کنند که در سیستم های یکپارچه قابل استفاده است.برنامه‌هایی که با گولنگ نوشته شده‌اند به طور معمول سریع‌تر از برنامه‌‎های نوشته شده با دیگر زبان‌های برنامه‌نویسی هستند و به شما کمک می کنند تا نرم‌افزهای پیچیده و جالب را توسعه دهید.از آنجایی که گولنگ یک زبان برنامه نویسی متن باز است، سورس‌کد آن به طور آزاد و رایگان قابل دسترس است. کامپایلر، کتابخانه‌ها، و ابزار آن نیز به طور رایگان برای همه قابل استفاده است.مزایای زبانگولنگ مزایای زیادی، هم شناخته شده و هم کمتر شناخته شده، دارد.لیستی بعضی از این مزایا:سادگی کدتعداد بی‌شماری از کتابخانه‌هاانعطاف‌پذیریروند ساخت مستقیم و سرراستدر واقع، سادگی هدف اصلی ایجاد زبان گو بود، که حاصل شد. گو ساختار نحوی (سینتکس) بسیاری ساده‌ای دارد که این امکان را می‌دهد تا اپلیکیشن‌ها را سریع‌تر از دیگر زبان‌ها توسعه دهید.دو مسئله جالب در مورد گولنگ وجود دارد.اولا، گولنگ توسط تازه‌کاران، افرادی که چیزی از زبان برنامه‌نویسی نمی‌دانند و می‌خواهند یک توسعه دهنده شوند، به راحتی قابل یادگرفتن است. گو تقریبا به راحتی پی‌اچ‌پی یا حتی پاسکال است، اما در عین حال به قدرت‌مندی سی‌پلاس‌پلاس.بله، ساختار نحوی در گولنگ بسیار نحیف و ناچیز است؛ و خبری از پیاده سازی تمام عیار شی‌گرایی در آن نیست. گو یک زبان تابعی است که می توان از آن برای حل مسائل در هر سطح پیچیدگی، مانند صنایع و کسب‌کارها، استفاده کرد.دوما، گولنگ توسط حرفه‌ای‌ها، که یک زبان یا چندین زبان برنامه‌نویسی را می‌دانند، می تواند فراگرفته شود. اغلب، توسعه‌دهندگان گو را بعد از تسلط یافتن در پایتون، پی‌اچ‌پی، سی‌پلاس‌پلاس، جاوا و سی‌شارپ یاد می‌گیرند.گولنگ همچنین شناخته شده برای داشتن تعداد عظیمی از کتابخانه‌ها و پکیج‌ها است که باعث می‌شوند بهره‌وری بیشتری با گو داشته باشید.مزیت شگفت‌انگیز بعدی، انعطاف‌پذیری این زبان است. روش گولنگ در انتزاع کردن داده‌ها و توسعه شی‌‎گراء به طرز قابل‌ توجهی انعطاف‌پذیر است.این زبان برنامه‌نویسی به نحوی طراحی شده که بتوان در آن سریع تسلط پیدا کرد و مسائل را به طور کارآمدتر حل کرد.در این زبان تنها 25 کلیدواژه وجود دارد و هیچ احتیاجی به مدیریت حافظه و نخ‌ها نیست، برای این کار از بازیافت حافظه یا زباله روبی (GC) و زمان‌بند (scheduler) استفاده می‌شود.25 کلیدواژه زبان گوآیا گولنگ میان شرکت‌ها بزرگ معروف است؟بدون هیچ شکی، گو تقریبا در تمامی شرکت‌ها و صنایع عظیم مورد استفاده است و تقاضا برای توسعه‌دهندگان آن بسیار است.این شرکت‌ها و صنایع، تبدیل‌کنندگان ویدیو، سرویس‌های استریمینگ، کسب‌وکارهای تجمعی، فروشگاه‌های آنلاین، پیام‌رسان‌های فوری (مثل تلگرام و واتس‌آپ) هستند. شما می توانید سطح تقاضا برای توسعه‌دهندگان گولنگ را با ارزیابی کردن فهرست سازمان‌هایی که پروژه‌ها/نرم‌افزارهایشان  با گو کار می‌کند، تخمین بزنید.لیستی از معرف‌ترین شرکت‌هایی که از گولنگ استفاده می‌کنند.GoogleTwitch (پلتفرم استرمینگ بازی)SendGrid (سرویس ابری ایمیل)Dropbox (یکی از پیشروترین شرکت ‌ها در خدمات رایانش ابری)SoundCloud (پلتفرم توزیع صدا به صورت آنلاین)گولنگ برای سیستم های پوش ‌نوتیفیکشن خوب، برای استریمیگ ایده‌آل، و بسیار سریع است چون زبانی ساده و کامپایل شده است. در نتیجه، شرکت‌های زیادی به دنبال توسعه‌دهندگانی هستند که حداقل کمی آشنایی با گو داشته باشند و آماده برای سوییچ کردن به این زبان برای یادگیری باشند.بنا بر آخرین تحقیقات، تمایل زیادی برای توسعه نرم‌افزازهایی که قبل با سی‌پلاس‌پلاس نوشته شده با زبان گو وجود دارد: مانند ‌سیستم‌های بک‌اند، ریاضیاتی، پردازش داده و منطق‌های کلیدی در حوزه کسب و کار.گولنگ برای ایجاد سیستم‌هایی با معماری میکروسرویس‌ها عالی است، بنابراین در آینده، تقاضا برای چنین برنامه‌نویسانی رشد خواهد کرد. از آنجایی که گو توسعه‌دهنده‌گان زیادی ندارد، بنابراین بیشتر به برنامه نویسان آن پرداخت خواهد شد.در جمع‌بندی، باید اقرار کنیم که گولنگ هم در روند توسعه و هم رشد شغلی یک زبان برنامه‌نویسی امیدوار‌کننده است. بدون شک، گولنگ زبان برنامه‌نویسی آینده است.خب اگر جذب گولنگ شده‌اید. باید اولین قدم‌ها را بردارید و سعی کنید آن را یادبگیرید. در سال‌های آینده، نیاز برای متخصصین در این صنعت رشد خواهد کرد.بهترین منبع که برای اطلاعات بیشتر در مورد زبان پیشنهاد می‌شود سایت رسمی گولنگ است. سایت رسمی دسترسی به داکیومنت ها، مشخصات زبان، پکیج های استاندارد و... را فراهم می‌کند. همچنین می توانید از آخرین آموزش‌ها چه به صورت متنی و ویدیویی بر روی وب استفاده کنید.شما می توانید برای گذاشتن قدم اول از اینجا گو را دانلود و نصب کنید.گو روز به‌ روز در حال محبوب شدن بین برنامه نویسان است، خب از شناس‌تان استفاده کنید و از امروز شروع به یادگیری آن کنید.مقاله اصلی </description>
                <category>انتشارات GoLang</category>
                <author>مصطفی جعفری</author>
                <pubDate>Wed, 23 Jun 2021 10:09:37 +0430</pubDate>
            </item>
                    <item>
                <title>پیاده سازی یک سرویس قابل تست در Golang - قسمت ۱</title>
                <link>https://virgool.io/golangpub/%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%DB%8C%DA%A9-%D8%B3%D8%B1%D9%88%DB%8C%D8%B3-%D9%82%D8%A7%D8%A8%D9%84-%D8%AA%D8%B3%D8%AA-%D8%AF%D8%B1-golang-%D9%82%D8%B3%D9%85%D8%AA-%DB%B1-zqlxusr66l33</link>
                <description>گو زبون قوی ایه. به صورت پیشفرض وقتی که نصبش میکنید روی سیستمتون با کتاب خانه‌های استاندارد خودش میتونید یک سیستم قوی بنویسید که پرفورمنس عالی ایی داشته باشه. نیازی به فریم ورک و .. ندارید که کدتون سریع تر و بهینه تر اجرا شه. این موضوع خیلی خوبه اما اگر از دنیای فریم ورک ها وارد Go شده باشید حتما براتون سوال هست خب چطور من کد بزنم؟ معماری نرم افزارم چطور باشه؟ چطور تست کنم و ...کوتاه کننده لینک، مثال همیشگیفرض کنید میخوایم یک سیستم کوتاه کننده لینک بزنیم. این سیستم ۲ تا وظیفه ساده رو میخواد انجام بده، بهش لینک بدیم و بهمون یک آدرس کوتاه شده بده، وارد آدرس کوتاه شده هم شدیم ما رو redirect کنه به آدرسی که بهش داده بودیم.چنین سیستمی رو خیلی راحت میشه زد. میگیم کلا ۲ تا route داره، توی اون route ها دیتابیس رو صدا میزنیم و از دیتابیس اطلاعات میگیریم. اگر قرار باشه سیستم ما دقیقا کارش این باشه و هیچ وقت هیچ تغییری توش نداشته باشیم خوب همین کد رو میزنیم میره پی کارش. اما الان درسته مثال ساده ایی زدیم ولی در نظر بگیریم سیستم ما یک مونولیت بزرگی میخواد بشه بعدا که کلی آدم روش کار میکنن و قراره تکنولوژی های جدیدی بهش اضافه بشه و فیچر بدیم و ... اینجاست که سوال اصلی مطرح میشه. معماری سیستم من چطور باشه؟ میتونیم خودمون طبق نظرمون یک معماری بزنیم و بریم جلو ببینیم جواب میده یا نه، یا از معماری های معمولی که بقیه هم باهاشون آشنا هستن مثل هگزاگونال و کلین و onion و ... استفاده کنیم.توی این مقاله میخوایم سیستم کوتاه کننده آدرس اینترنتیمون رو با معماری ایی شبیه هگزاگونال پیاده سازی کنیم. می بینیم چقدر فرایند تست و توسعه راحت تر میشه و در آینده کارمون برای بزرگتر شدن سیستم بی دردسر تر میشه.معماری هگزاگونال چی میگه؟اول ببینیم نرم‌افزاری که معمولا میزنیم چیه؟ وقتی به نرم‌افزار میگیم فلان URL رو کوتاه کن ما از طریق HTTP داریم به نرم‌افزار دستور میدیم. حالا این اتفاق میتونست توسط web socket اتفاق بیوفته! اصلا نه، ما میتونستیم یک command line داشته باشیم و یک دستور بدیم که فلان URL رو بساز. توی این حالت روشی که به نرم‌افزار دستور میدیم فرق میکنه. اما همیشه به نرم افزار یک URL میدیم و ازش یک URL کوتاه شده میخوایم. منطق و بیزینس لاجیک نرم افزار ثابته ولی اینکه چطور باهاش صحبت میکنیم فرق میکنه.حالا از یک زاویه دیگه نگاه کنیم. دیدیم که ما داریم به سیستممون یک سری دستور میدیم اما خود سیستم هم با یک سری بازیگر های دیگه کار داره! مثلا وقتی میگیم فلان آدرس رو کوتاه کن سیستم باید آدرس جدید و آدرس قدیمی رو یک جا ذخیره کنه. حالا میتونه دیتابیس SQLایی باشه، مونگو باشه، توی فایل و ردیس. توی دو بند بالا دیدیم سیستم ما ۲ تا وابستگی داره که باهاشون یا صدا زده میشه یا سیستم اون ها رو صدا میزنه. اما اینکه اون ها چطور انجام میشن تاثیری در هسته سیستم ما نداره. وقتی میخوایم URL بسازیم باید یک رشته تصادفی تولید کنیم، بررسی کنیم آدرسی که به ما دادن آدرس اینترنتی درستی هست یا نه و در نهایت بدیم که ذخیره بشه. اینکه چطور ذخیره میشه دیگه به هسته سیستم ما ربطی نداره.برای اینکه به چنین چیزی برسیم میتونیم از معماری هگزاگونال استفاده کنیممعماری هگزاگونالدر این معماری ما دو تا ۶ ضلعی داریم. ۶ضلغی داخلی تعریف کننده هسته‌ی برنامه ماست.توی هسته ما کد های لاجیک ما قرار میگیرد. بیزینس لاجیک ما از طریق یک سری port (درگاه) با بیرون ارتباط برقرار میکنند. ما دو نوع port داریم:پورت های Driving: از طریق این درگاه ها اپلیکیشن ما صدا زده شده و عملیات خاصی که میخواهیم انجام میشود. به این‌ها پورت های ورودی هم میگیم چون اولین پورتی هستن که دنیای خارج صدا میزنه.پورت‌های Driven: این درگاه ها توسط اپلیکیشن صدا زده میشوند (مانند دیتابیس، سرویس SMS، کش و ..)همونطوری که گفتیم ۶ضلعی داخلی هسته و لاجیک ما هست که از طریق یک سری درگاه با دنیای خارج صحبت میکنه. حالا ۶ ضلعی خارجی ما میشه پیاده‌سازی های اون پورت ها که بهش آداپتر ها هم میگیم.پروژه Go رو بسازیممن یک پروژه Go ایی با go modules ساختم که میخوایم سرویس کوتاه کننده لینک رو توش پیاده سازی کنیم. اول از همه یک پوشه به اسم internal میسازم که کد های مربوط به سرویسمون رو اونجا بیاریم.اول ببینیم چه دیتاهایی قراره داشته باشیم. توی پوشه internal یک پوشه به اسم models میسازیم که پکیج نگه‌داری مدل هامون رو داشته باشیم. توی پوشه models هم اولین مدلمون یعنی URL رو میسازیم:پکیج models رو برای ساخت مدل هامون استفاده میکنیممیدونیم که قراره مدل URL ما یک کلید کوتاه مختص به خودش داشته باشه و همچنین یک فیلد redirect هم میخوایم که مشخص کنه کجا میخوایم کاربر رو redirect کنیم:type URL struct {
   Key       string
   Redirect  string
   CreatedAt int64
}حالا port هامون رو مشخص میکنیم. توی پوشه internal یک پوشه برای پکیج ports میسازیم. همونطوری که گفتیم دو نوع پورت داریم که توی دو فایل مختلف به نام های incoming و outgoing تعریفشون میکنیم (اسم ها برای من اینطور واضح ترن)حالا با استفاده از یک اینترفیس تعریف میکنیم که پورت های outgoing ما میخوان چطور باشن (بعدا آداپتور ها باید این اینترفیس ها رو پیاده سازی کنند، مثلا دیتابیس SQLایی)type URLRepository interface {
   Save(ctx context.Context, url *models.URL) error
   Find(ctx context.Context, code string) (models.URL, error)
}و همینکار رو هم برای پورت های incoming هم میکنیم (پورت هایی که صدازده میشن. مثلا rest ما صدا میزنه که فلان url رو بساز)type URLService interface {
   Save(ctx context.Context, url *models.URL) error
   Find(ctx context.Context, code string) (models.URL, error)
}چون مثال ما ساده هست service ما خیلی شبیه repository میشه. توی مرحله اول کار service اینه یک ولیدیشن ساده روی دیتاها انجام بده و یک کلید تصادفی به URL بده  و در نهایت برای repository بفرسته که ذخیره بشن. اما یکم جلوتر cache رو هم اضافه میکنیم که می بینیم کارمون چقدر راحت تر میشه.حالا پورت ها رو ساختیم. چیکار کنیم؟ میدونیم همه چیزی که هسته ما نیاز داره رو داریم. شروع میکنیم به نوشتن هسته. اولین چیزی که باید پیاده سازی کنیم سرویس URLهست. برای این کار توی internal یک فایل به اسم url.go میسازم:type urlService struct {
   urlRepository ports.URLRepository
}

func (u urlService) Save(ctx context.Context, url *models.URL) error {
   url.CreatedAt = time.Now().Unix()
   url.Key = shortid.MustGenerate()
   return u.urlRepository.Save(ctx, url)
}
func (u urlService) Find(ctx context.Context, code string) (models.URL, error) {
   return u.urlRepository.Find(ctx, code)
}کاری که ما کردیم اینه اطلاعاتی که گرفتیم رو یکم ویرایش کردیم و برای مدلمون زمان ساخت رو براساس زمان timestamp فعلی ست کردیم و یک کلید رندوم با استفاده از پکیج shortid ساختیم و دادیم به دیتابیس و اطلاعاتی که دیتابیس به ما میده رو مستقیم داریم بر میگردونیم. اما مثلا اگر به ما URL اشتباهی دادن چه اتفاقی میوفته؟ من میخوام یک validation به لایه service مون اضافه کنم. برای این کار اول مدل URLرو اینطور عوض میکنم که از پکیج go-playground/validator بتونم استفاده کنم:type URL struct {
   Key       string
   Redirect  string `validate:&amp;quotrequired,url&amp;quot`
   CreatedAt int64
}و توی سرویسمون هم اینطور ورودی رو validate میکنیم.import (
   &amp;quotcontext&amp;quot
   &amp;quoterrors&amp;quot
   &amp;quotgithub.com/mhrlife/kootah/internal/models&amp;quot
   &amp;quotgithub.com/mhrlife/kootah/internal/ports&amp;quot
   errs &amp;quotgithub.com/pkg/errors&amp;quot
   &amp;quotgopkg.in/go-playground/validator.v9&amp;quot
)

var (
   ErrInputValidationFailed = errors.New(&amp;quotinput validation failed&amp;quot)
)

type urlService struct {
   urlRepository ports.URLRepository
   validator     *validator.Validate
}

func NewUrlService(urlRespository ports.URLRepository) ports.URLService {
   return &amp;urlService{
      urlRepository: urlRespository,
      validator:     validator.New(),
   }
}

func (u urlService) Save(ctx context.Context, url *models.URL) error {
   if err := u.validator.Struct(url); err != nil {
      return errs.Wrap(ErrInputValidationFailed, err.Error())
   }
   url.CreatedAt = time.Now().Unix()
   url.Key = shortid.MustGenerate()
   return u.urlRepository.Save(ctx, url)
}

func (u urlService) Find(ctx context.Context, code string) (models.URL, error) {
   return u.urlRepository.Find(ctx, code)
}من یه سری کار کردم. اول از همه یک ارور جدید تعریف کردم به اسم ErrInputValidationFailed که با استفاده از اون اگر ورودی هام مشکل داشتن بتونم ارور برگردونم. برای اینکه بتونم validation هم انجام بدم باید یک validator میساختم. همیشه برای اینکه یک تایپ خاص رو بسازیم معمولا تابع NewTypeName میسازیم که توش هم مقدار دهی اولیه انجام بدیم و در نهایت آبجکتی که ساختیم رو خروجی بدیم. اگر توجه کنید نوع خروجی ما اینترفیس سرویسی هست که قبلا ساخته بودیم. در نهایت هم قبل از اینکه بخوایم چیزی ذخیره کنیم کار validation رو انجام میدیم.چرا این همه خودمون رو اذیت کنیم؟ احتمالا این سوالیه که الان توی ذهنتون شکل گرفته. مثالی که ما میزنیم مثال ساده ایی هست که فقط یک repository داره و یک کار ساده انجام میده. اگر پروژه بزرگتر بشه این معماری میتونه جلوی خیلی از پیچیدگی ها رو بگیره و تست مارو ساده تر کنه. راستی چطور بفهمیم کدی که زدیم درست؟نوشتن تست و اجرای آنبرای اینکه متوجه بشیم لاجیکی که نوشتیم درست کار میکنه یا نه باید تستش کنیم. اما الان ما آداپتوری نداریم. دیتابیسی نداریم. postman ایی نداریم که درخواست HTTP بزنه. چطور تست کنیم؟معماری هگزاگونال به ما این امکان رو میده بیزینس لاجیک رو بدون نیاز به هیچگونه آداپتوری (دیتابیس، REST و...) تست کنیم. چون اصلا هدف کار ما این بود. ما کدی زدیم که لایه لاجیک رو از همه چیز جدا کنیم.برای اینکه تست کنیم از mock کردن استفاده میکنیم. یعنی چون interface هایی که لاجیک ما بهشون نیاز داره رو داریم یک تایپ mock میسازیم که کارای اون اینترفیس ها رو تقلید کنیم.  تست هایی که مینویسیم لایه  لایه خواهد بود. یعنی توی لایه بیزینس لاجیک در نظر میگیریم که آداپتور های ما همیشه درست کار میکنن و بعدا وقتی آداپتور ها رو مینویسیم براشون تست ایی مینویسیم که فقط اون ها رو تست کنن.برای مثال اگر میخوایم ببینیم لاجیک ما درست کار میکنه برای تابع Save که خیلی سادست یک تست مینویسیم که URL اشتباه باشه و یک تست که URL درست باشه (تنها لاجیک ما در این مثال ساده همین بوده). بیاید همین الان همین کار رو بکنیم. برای نوشتن ماک و تست کردن از کتابخانه mockery و testify استفاده میکنیم. با استفاده از کامند زیر برای تک تک اینترفیس هامون یک فایل mock میسازیم:mockery --allاین ابزار ماک های ما رو در یک پوشه به نام mocks قرار میده و بعدا از این پکیج میتونیم استفاده کنیم.  برای نوشتن تست های urlمون توی پوشه internal کنار فایل url یک فایل به نام url_test.go میسازم.اولین تستی که میخوایم بنویسیم اینه که یک URL درست بدیم و انتظار داریم Save ریپازیتوری Url صدا زده بشه و یک مقدار random برای کلید URL ست بشه.  برای این کار اینطور تستی مینویسیم:func TestUrlService_SaveSuccessful(t *testing.T) {
   urlRepMock := &amp;mocks.URLRepository{}
   logicUrl := NewUrlService(urlRepMock)
   ctx := context.Background()

   urlRepMock.On(&amp;quotSave&amp;quot, ctx, mock.AnythingOfType(&amp;quot*models.URL&amp;quot)).Return(nil)

   url := models.URL{Redirect: &amp;quothttps://google.com&amp;quot}
   err := logicUrl.Save(ctx, &amp;url)

   assert.Equal(t, nil, errs.Cause(err))
   assert.NotEqual(t, &amp;quot&amp;quot, url.Key)

   urlRepMock.AssertExpectations(t)
}برای اجرای تست:go test ./...اول اومدیم یک logic با استفاده از mockمون ساختیم. mockبه ما این قابلیت رو میده بهش بگیم انتظار چه ورودی هایی داشته باشه و هر کدوم رو گرفت چه رفتاری نشون بده. برای مثال گفتیم اگر Save صدا زده شد ورودی اولت باید context ایی باشه که اول ساختیم و ورودی دوم از تایپ models.URL و وقتی این رو گرفتی nil برگردون (یعنی ارور نخوردیم)حالا وقتی logicUrl.Save صدا زده میشه توی لاجیک متد Save از urlRepository هم صدا زده میشه که طبق mockمون عمل میکنه. در آخر برای اینکه متوجه بشیم تست ما درست انجام شده چک میکنیم که ارورمون حتما nil باشه و اینکه توی تابع برای Key یک مقدار تصادفی ست شده باشه. در نهایت هم با AssertExpectations هم به Mock میگیم چک کن تمام انتظاراتی که داشته برآورده شده اند یا نه.حالا یک تست جدید مینویسیم که انتظار داریم ارور دریافت کنیم چون میخوایم جای urlیک عبارت اشتباه بدیم:func TestUrlService_SaveErrValidation(t *testing.T) {
   urlRepMock := &amp;mocks.URLRepository{}
   logicUrl := NewUrlService(urlRepMock)
   ctx := context.Background()

   url := models.URL{Redirect: &amp;quotrandom text&amp;quot}
   err := logicUrl.Save(ctx, &amp;url)

   assert.Equal(t, ErrInputValidationFailed, errs.Cause(err))

   urlRepMock.AssertExpectations(t)
}توی این تست صرفا چک کردیم که حتما error بگیریم و ارورمون ErrInputValidationFailed  باشه.جمع بندیما با استفاده از این معماری تونستیم بیزینس لاجیکمون رو بدون بالااوردن دیتابیس و نوشتن یک سرویس RESTو... تست کنیم. اینطور باعث میشه سرعت کارمون هم بیشتر بره بالا هم بخاطر تست هایی که مینویسیم کدمون در آینده قابل اعتماد تر باشه.در مقاله بعدی آداپتور ها رو مینویسیم و یک لایه کش هم به سرویسمون اضافه میکنیم.</description>
                <category>انتشارات GoLang</category>
                <author>محمد حسینی راد</author>
                <pubDate>Wed, 02 Jun 2021 22:29:19 +0430</pubDate>
            </item>
                    <item>
                <title>مقدمه ایی بر فریم ورک gin (gin-gonic web framework)</title>
                <link>https://virgool.io/golangpub/%D9%85%D9%82%D8%AF%D9%85%D9%87-%D8%A7%DB%8C%DB%8C-%D8%A8%D8%B1-%D9%81%D8%B1%DB%8C%D9%85-%D9%88%D8%B1%DA%A9-gin-gin-gonic-web-framework-skssyoumcvcx</link>
                <description>gin gonicهمونطور که میدونید یا نمیدونید gin-gonic یکی از فریم ورک های زبان go یا بهتره بگم golang هست و اگه نمیدونید فریم ورک چیه میتونید از لینک های زیر استفاده کنید :https://en.wikipedia.org/wiki/Web_frameworkhttps://zerotohero.ir/article/web-development/%D9%81%D8%B1%DB%8C%D9%85-%D9%88%D8%B1%DA%A9-%D9%88%D8%A8-%DA%86%DB%8C%D8%B3%D8%AA-%D9%88-%DA%86%D8%B1%D8%A7%D8%9F/https://hackr.io/blog/what-is-frameworksاگه بخواییم خیلی خلاصه بگیم فریم ورک یه چارچوب یا یه پایه است که باعث شده کارای تکراری که توی همه ی برنامه های اون حوزه(مثلا وب) انجام میشه رو انجام ندیم و از اونجایی که ما ادم های تنبلی هستیم و معمولا افراد با تجربه ایی این فریم ورک ها رو ساختن پس استفاده از اونا خیلی توصیه میشه چون باعث میشه درگیر یه سری کارای تکرای یا خیلی پایه ایی نشین.حالا که تقریبا فهمیدیم فریم ورک چیه وقتشه که با gin که فریم ورک وب زبان go هست اشنا بشیم و یه سری نمونه کد بزنیم.تعریفی که توی ریپوزیتوری اصلی خود gin هست اینه : این لینک سایت رسمیشه و این لینکش توی گیت هابهGin is a web framework written in Go (Golang). It features a martini-like API with much better
performance, up to 40 times faster thanks to httprouter. If you need performance and good
productivity, you will love Gin.به زبان ساده ، Gin یک میکرو فریم ورک Go مبتنی بر httprouter  که خدمات API مشابه martini (یکی دیگه از فریم ورک های go) اما با عملکرد بهتره.جین سرعت بالایی داره و دارای قابلیت های خیلی خوبی مثل مدیریت ارور (error handling)، پشتیبانی از میان افزار ها (Middlewares) و پردازش json برخورداره که باعث میشه سرعتتون بالا بره و به همین دلایله که استفاده ازش توصیه میشه.میتونیم از نتایج بنچ مارک چنتا از فریم ورک های go برای مقایسه gin با بقیه فریم ورک های رقیبش هم که توی ریپوزیتوریه اصلیش اومده هم استفاده کنیم که جوری که این امار نشون میده مثل اینکه gin نسبت به بقیه فریم ورک ها امتیاز بیشتری داره.https://github.com/gin-gonic/ginالبته گفتن این نکته ضروریه که این چنین مقایسه ها ممکنه یه جور جبهه گیری بوجود بیارن که خیلی عوامل دیگه روی سرعت و کیفیت یه API تاثیر گذارن که فقط یکیشون فریم ورکه پس اینجور مقایسه ها زیادم مهم نیستن.خب حالا وقتش رسیده یه خورده کد بزنیم ببینیم چطور کار میکنه :اول از همه باید خود زبان go رو روی سیستمتون نصب کرده باشید . اگه نصبش نکردید میتونید از سایت اصلیش دانلود کنید و نصب کنید :https://golang.org/doc/installبعدش یه پوشه میسازیم و go mod init go-intro رو میزنیم تا پروژمون initialize بشه و بتونیم پروژمون رو پکیج بندی کنیم و در نهایت باید gin رو با استفاده از go نصب کنید که یه چیزی شبیه به زیر میشه :حالا یه فایل به اسم main.go بسازید و با یه ادیتور اونو باز کنید و کدای زیر رو توش بنویسین : توی خط اول که پکیجو برای گو تعریف کردیم که با توجه به اینکه برنامه ما از تابع main . پکیج main اجرا میشه پس اسم پکیجو main میذاریم.توی خط سوم gin رو که از طریق go get نصب کرده بودیم رو ایمپورت میکنیم تا بتونیم از function ها و struct هاش استفاده کنیم.توی خط ۷ ام ما یه متغیر به اسم router تعریف و مقدار دهی کردیم که همون روترمون هست و فانکشن دیفالت در واقع یه روتر میده میده که شامل دوتا میان افزار middleware خودشه.حالا روتر ما یه سری فانکشن داره که همون متد های http ان مثل POST, GET, PUT, PATCH, DELETE, ...  که هرکدومو که بزنید آرگمان اول یه رشته میگیره که همون مسیره api و پارامتر دوم یه فانکشنه که اینجا میشد یه فانکشن توی همین فایل ( یا کلا توی پکیج دیگه ) تعریف کرد بعد فقط اسمشو نوشت . مثل چیزی که این پایین نوشتم : اگه درست نمیدونید پروتوکل http چیه و متداش به چه دردی میخورن میتونید از این لینکایی که گذاشتم استفاده کنید :https://developer.mozilla.org/en-US/docs/Web/HTTP/Overviewhttps://developer.mozilla.org/en-US/docs/Web/HTTP/Methodsتوی کد بالا فانکشن هایی که به عنوان ورودی به یکی از متد های router اضافه میشن یه ارگمان میگیرن از جنس(خود) gin.Contex که یه struct از gin که یه سری متد داره برای خروجی دادن(به انواع فرمت ها که الان ما json رو انتخاب کردیم) و گرفتن ورودی(کوری پارامتر ها یا دیتا هایی که توی body ارسال میشن) که بعدا باهاشون کار میکنیم و آرگمان اولی که به فانکشن JSON دادیم (200) همون http Status Code ما هست که اینجا موفقیت امیز بوده برای همین 200 . لیست status code ها رو میتونید اینجا ببینید.حالا اگه دستور go run main.go رو بزنیم برنامه مون اجرا میشه :و میتونید توی مرورگرتون localhost:8080/home رو بزنید تا خروجی رو بهتون نشون بده.این لاگ هایی که توی ترمینال میبینید در واقع به خواطر یه middleware که توی خود gin هست و بالا تر که گفتم router.Default شامل ۲ تا middleware میشه یکیشون همینه اسمش logger حالا بعدا خودمون میتونیم middleware تعریف کنیم و استفاده کنیم.خب حالا ما یه api خیلی ساده ساختیم که فقط یه api داره اونم یه json خروجی میده. برای اینکه api پیشرفته ایی بسازیم باید یه سری ساختار و پوشه بندی(پکیج) به برنامه مون اضافه کنیم که ما از معماری MVC برای ساخت api هامون استفاده میکنیم که همون ساختارمونه.حالا اگه نمیدونید فرمت json چطوریه میتونید از لینکهای زیر استفاده کنید:https://www.w3schools.com/whatis/whatis_json.asphttps://blog.faradars.org/json-overview/و اگه نمیدونید معماری MVC چطوره و middleware کجای کار قرار میگیره از لینکای زیر استفاده کنید:https://blog.faradars.org/mvc-%DA%86%DB%8C%D8%B3%D8%AA-%D8%9F/https://www.educative.io/blog/mvc-tutorialنمای کلی معماری MVCدر ادامه سعی میکنم طی چند قسمت چگونگی ساخت یه api نسبتا پیشرفته رو توضیح بدم.شاد و موفق باشید.</description>
                <category>انتشارات GoLang</category>
                <author>Amirreza saki</author>
                <pubDate>Sun, 30 May 2021 19:23:32 +0430</pubDate>
            </item>
                    <item>
                <title>راست در مقابل Go , کدام را انتخاب کنیم؟</title>
                <link>https://virgool.io/golangpub/%D8%B1%D8%A7%D8%B3%D8%AA-%D8%AF%D8%B1-%D9%85%D9%82%D8%A7%D8%A8%D9%84-go-%DA%A9%D8%AF%D8%A7%D9%85-%D8%B1%D8%A7-%D8%A7%D9%86%D8%AA%D8%AE%D8%A7%D8%A8-%DA%A9%D9%86%DB%8C%D9%85-oivo0dbldyrt</link>
                <description>در کمتر از یک دهه ، دو زبان برنامه نویسی جدید به عنوان گزینه های اصلی برای توسعه شرکتها ظاهر شده اند: Go که توسط Google ایجاد شده. و Rust که توسط Mozilla ایجاد شده است. در این مقاله به همه چیز درباره Rust در مقابل Go می پردازیم.مزایای زبان Rust و مزایای زبان Goهر دو زبان ویژگی های ضروری را برای توسعه نرم افزارهای مدرن ارائه می  دهند: یک دسته ابزار پیچیده و یکپارچه . ایمنی حافظه ، مدل توسعه منبع باز و  پشتیبانی قوی کاربران.جدا از این شباهت ها ، Rust و Go تفاوت های چشمگیری دارند.هر کدام برای  استفاده از یک جای خاص ، تحقق خواسته های مختلف و نوشتن انواع مختلف برنامه  ها ساخته شده اند.بنابراین ، مقایسه Rust و Go مربوط به این نیست که کدام زبان .”از نظر  عینی بهتر است”. ، بلکه در مورد اینکه کدام زبان برای یک کار برنامه نویسی  خاص بهتر عمل می کند است. با این حساب ، بیایید به اصلی ترین تفاوت های  Rust و Go توجه کنیم .و ببینیم چه کاری برای کدام یک مناسب تر است.راست در مقابل Go , کدام را انتخاب کنیم؟راست در برابر Go: عملکرددر لیست مزایای مهم Rust ، عملکرد با ایمنی و سهولت در بالاترین رتبه  قرار دارد. و ممکن است حتی مزیت شماره یک آن باشد. برنامه های Rust به گونه  ای طراحی شده اند که به سرعت یا تقریبا هم سرعت با زبان C و ++C اجرا  شوند.نوشتن یک برنامه کند در Rust همیشه امکان پذیر است . اما حداقل می  توانید مطمئن باشید که Rust عملکرد را برای ایمنی یا راحتی قربانی نمی کند.  آنچه Rust انجام می دهد ، تلاشی از سوی توسعه دهنده برای یادگیری و تسلط  بر انتزاعات زبان برای مدیریت حافظه است.درعوض زبان Go ، برای راحتی کار توسعه دهنده ، سرعت را تا حدودی فدا می  کند. مدیریت حافظه توسط ران تایم Go انجام می شود . بنابراین مقدار اجتناب  ناپذیری هزینه اضافه مربوط به زمان اجرا وجود دارد. اما در بسیاری از  سناریوها ، این معامله قابل اغماض است. Go به طور پیش فرض چندین برابر  سریعتر از سایر زبانهای راحتی مانند پایتون است .با این هزینه کوچک برای  برنامه نویس که باید برای همه آبجکت ها type های قوی تعریف کند. .(راحتی و  انعطاف پذیری پایتون در عملکرد آن تاثیر قابل توجهی دارد.)به طور خلاصه ، Rust سریعتر است . اما برای اکثر موارد استفاده در روز ،  اختلاف سرعت بین Rust و Go ناچیز و قابل چشم پوشی خواهد بود. در مواردی که  عملکرد- نیاز و خواسته ی شماره یک است ، Rust می تواند از راه هایی که  Goدر آن عاجز است عالی باشد.راست در مقابل Go: مدیریت حافظهمدیریت حافظه در Rust و Go به شدت با عملکردهای این دو زبان ارتباط دارد.مدیریت حافظه RustRust از استراتژی های ownership زمان کامپایل برای مدیریت حافظه از طریق  انتزاعات با هزینه صفر استفاده می کند. این بدان معناست که اکثریت قریب به  اتفاق مشکلات مربوط به مدیریت حافظه را می توان قبل از اجرای مستقیم  برنامه برطرف کرد. اگر برنامه Rust از لحاظ حافظه امنیت نداشته باشد  ،کامپایل نمی شود. با توجه به اینکه چه مقدار از دنیای امروز ما بر بستر  نرم افزارهایی ساخته شده است که به دلیل مدیریت نامناسب حافظه ، معمولاً  ناامن است.روش Rust نه تنها عالی است بلکه می شود گفت کاش زودتر از این ها  آمده بود!همانطور که در مقاله قبلی اشاره شد . این ایمنی به بهای یادگیری نسبتا  سخت زبان Rust به دست می آید: برنامه نویسان باید بدانند که چگونه از  اصطلاحات مدیریت حافظه Rust به درستی استفاده کنند . و این به زمان و تمرین  نیاز دارد. توسعه دهندگانی که از دنیای ++C , C و #C یا جاوا می آیند باید  هنگام کار با Rust در مورد نحوه نوشتن کدشان تجدید نظر کنند.توجه داشته باشید که کارگذاری امکان جمع آوری زباله به طور جداگانه ،  بعنوان یک موردthird-party در Rust وجود دارد. برای مثال می توان به  جعبه gc ، اشاره کرد . اگرچه هنوز هم در مراحل ابتدایی است. اما الگوی زیربنایی Rust از جمع آوری زباله استفاده نمی کند.مدیریت حافظه Goمانند راست، Go نیز از از نظر حافظه امن است . اما دلیل آن این است که  مدیریت حافظه در زمان اجرا به طور خودکار انجام می شود. برنامه نویسان می  توانند هزاران خط کد Go را بنویسند و هرگز مجبور نیستند به فکر تخصیص یا  آزادسازی حافظه باشند. برنامه نویسان در زمان اجرا تا حدی کنترل جمع کننده  زباله را دارند. برای جلوگیری از تداخل چرخه جمع آوری زباله در عملیات ، می  توانید آستانه جمع آوری زباله را تغییر داده یا به صورت دستی جمع آوری کنید.برنامه نویسان همچنین می توانند برخی از مدیریت های حافظه دستی را در Go  انجام دهند. اما این زبان عمداً در برابر انجام این کار مانع ایجاد می  کند. به عنوان مثال ، برای دستیابی به متغیرها می توانید از اشاره گرها  استفاده کنید ، اما برای دسترسی به مناطق دلخواه حافظه نمی توانید محاسبات  اشاره گر را انجام دهید .مگر اینکه ازبسته unsafeاستفاده کنید ، گزینه ای  نا معقول برای نرم افزاری که در حال تولید است.اگر به برنامه نویس گفته شده نیاز به تخصیص و آزادسازی حافظه به صورت  دستی دارد . مثلاً برای سخت افزارهای سطح پایین یا سناریوهایی که به حداکثر  عملکرد نیاز است – Rust برای تأمین این نیازها طراحی شده است. نباید تصور  کنید که مدیریت حافظه خودکار Go آن را برای انجام این کار نامناسب می کند .  اما Rust ثابت کرده است که در برخی سناریوهایی که کارایی بالا مد نظر است  مناسب است.در یکی از نمونه های اخیر ، Discord یکی از اصلی ترین سرویس های خود را از Go به Rust تغییر داده است . بخشی از این مسئله به دلیل مشکلات  مربوط به مدل حافظه Go و جمع آوری زباله است. نسخه Rust این سرویس در نسخه  های اولیه و بدون هیچ گونه تنظیم دستی ، از نسخه Go بهتر عمل کرد.شرکت هایی که از Go استفاده می کنندراست در برابر Go: سرعت توسعهگاهی اوقات سرعت توسعه از سرعت خود برنامه مهمتر است. پایتون از این  لحاظ که سریعترین زبان برای اجرا نیست . اما در میان سریعترین زبانها برای  نوشتن نرم افزار است به محبوبیت این چنینی رسیده. Go نیز همین جذابیت را  دارد. مستقیم و سادگی آن باعث می شود یک روند توسعه سریع انجام شود. زمان  کامپایل کوتاه است و زمان اجرای Go از پایتون .(و سایر زبانهای interpreted  ، که کار توسعه دهنده با آن ها راحت است). سریع تر است.سرعت توسعه Goبه طور خلاصه ، Go هم سادگی و هم سرعت را ارائه می دهد. پس چه چیزی از  دست رفته است؟ برخی از ویژگیهای یافت شده در زبانهای دیگر .(به عنوان مثال  ،generics). که برای سهولت در یادگیری زبان ، تسلط آسانتر و نگهداری آسانتر  یافت می شوند از آن حذف شده است. نکته منفی این است که با این حذف برخی از  کارهای برنامه نویسی بدون انجام مقدار قابل توجهی کار و تکرار واضحات در  خود کد امکان پذیر نیست. کار برای افزودن generics به Go در حال انجام است .  اما این کار همچنان در حال پیشرفت است و تغییر به Go جدیدی که از مواد  generics استفاده می کند ، نیاز به بازنویسی کردن دوباره مقدار زیادی کد  موجود دارد.سرعت توسعه RustRust دارای ویژگی های زبانی بیشتری نسبت به Go است .بنابراین یادگیری و  تسلط آن به زمان بیشتری نیاز دارد. مدت زمان کامپایل Rust نیز طولانی تر از  برنامه های معادل Go است . به ویژه برای برنامه های کاربردی با dependency  بزرگ. این امر حتی پس از تلاش بسیار پروژه Rust برای کوتاه کردن زمان  compile، همچنان به قوت خود باقی است.اگر یک چرخه توسعه سریع و نیاز به حضور سریع افراد در یک پروژه از  اولویت های اصلی است . Go بهترین انتخاب است. اگر کمتر به فکر سرعت توسعه  هستید و بیشتر به ایمنی حافظه و سرعت اجرا توجه دارید ، Rust را انتخاب  کنید. در هر صورت ، اگر تیمی دارید که قبلاً با یکی از این دو زبان کار  کرده اند و تجربه دارند ،همان زبان را انتخاب کنید.شرکت هایی که از Rust استفاده می کنندراست در برابر Go: همزمانی و موازی کاریسخت افزارهای مدرن چند هسته ای هستند و برنامه های مدرن به صورت شبکه ای  و توزیع شده اند. زبانهایی که برای این موارد برنامه ای ندارند در پشت  پرده قرار می گیرند. برنامه نویسان باید بتوانند وظایف را به طور مستقل ،  چه در یک موضوع یا چند موضوع ، اجرا کنند و وضعیت را بین وظایف به اشتراک  بگذارند بدون اینکه خطر خرابی داده ها را در بر داشته باشد. Rust و Go هر  دو روشهایی برای انجام این کار ارائه می دهند.همزمانی در Goهمزمانی(Concurrency) از ابتدا با استفاده از goroutines(رشته های سبک) و  کانال ها (مکانیسم های ارتباطی برای goroutines) در syntax زبان Go قرار  داده شده. این قابلیت ها نوشتن برنامه هایی (مانند سرویس های شبکه) را که  باید بسیاری از کارها را همزمان انجام دهند بدون این که مشکلاتی رایج مانند  مشکل race conditions پیش آید را ساده می کند . زبان گو race conditions  را غیرممکن نمی کند . اما مکانیسم های تست بومی را فراهم می کند تا در صورت  پیش آمدنrace conditions در زمان اجرا ، به برنامه نویس هشدار دهد.همزمانی در Rustراست syntax همزمانی بومی را در قالب کلمات کلیدی async/.await ، با نسخه 1.39.0 در اواخر 2019ارایه داد. قبل از async/.await این امر از طریق یک جعبه یا بسته برای Rust به نام futures محقق می شد. اگرچه همزمانی در Rust سالها تجربه توسعه دهنده پشت Go را  ندارد . اما مزیت ایمنی حافظه Rust اینجا به کمکش می آید . به این معنی که  کد Rust که می تواند race conditions را بروز دهد ، کامپایل نمی شود. نوشتن  کد برای عملیات همزمانی یا asynchronous در زبان Rust سخت تر خواهد بود  .(به دلیل قوانین syntax این زبان). اما در دراز مدت ماندگاری بالایی دارد.راست در مقابل Go: قابلیت سازگاری با کد قدیمیزبانهای جدیدی مانند Rust و Go با هدف ایمنی حافظه و سهولت برنامه نویسی  از راههایی که زبانهای قبلی در آن عاجز بودند ، به وجود آمدند. اما جدید  همیشه باید تا حدی با قدیم همزیستی داشته باشد. برای این منظور ، Rust و Go  هر دو با کد C قدیمی همکاری می کنند ، اگرچه با محدودیت هایی مختلف در هر  مورد.سازگاری در RustRust می تواند از طریق کلمه کلیدی extern و “جعبه” libc  (نام Rust برای یک بسته) مستقیماً با کتابخانه های C صحبت کند. اما این  ارتباط ها با این کتابخانه ها باید به عنوان ناامن(unsafe) برچسب گذاری  شوند. به عبارت دیگر ، Rust نمی تواند ایمنی حافظه آنها را تضمین کند. شما  باید به طور دستی از ایمن بودن رابط های کد C اطمینان حاصل کنید . بسیاری از نمونه های نحوه بسته بندی کد با FFI Rust (رابط کاربری خارجی)  – برای C و سایر زبانها – را می توان در وب سایت Rust FFI Omnibus یافت .پروژه های دیگری از سیستم Rust و ویژگی های تجزیه و تحلیل استاتیک برای  ایجاد یک پل امن بین زبان ها استفاده می کنند. به عنوان مثال ، پروژه CXX اتصال ایمن به ++C از Rust را فراهم می کند.سازگاری در Goزبان Go بسته cgo را برای کار با C ارایه می دهد . این  بستهcgo به شما امکان می دهد تا از کتابخانه های C فراخوانی کنید. از  پرونده های هدر C در کد Go خود استفاده کنید و انواع داده های متداول را  بین C و Go تبدیل کنید (به عنوان مثال رشته ها). با این حال ، از آنجا که  Go توسط مدیریت حافظه و زباله جمع می شود ، باید اطمینان حاصل کنید که pointer هایی که به C منتقل می کنید به درستی مدیریت می شوند. cgo همچنین تمایل به ایجاد هزینه سربار برای هر  ارتباط دارد ، به این معنی که همیشه از این که مستقیم با C کار کنید کندتر  خواهد بود.به طور خلاصه ، Rust نسبت به Go در زمینه تعامل با C کمی دوستانه تر است  .بنابراین هر چیزی که وابستگی عمده ای به C داشته باشد می تواند نوک پیکان  را به سمت Rust تغییر دهد. هر چند هم در Rust و هم در Go ، تعامل با C  برای توسعه دهنده هزینه هایی دارد: سرباری بیشتر ، زمان کامپایل کندتر ،  ابزار پیچیده تر ، debugging سخت تر.توجه داشته باشید که Rust و Go همیشه می توانند در سطوح بالاتر کد نیز  ارتباط برقرار کنند – به عنوان مثال ، مبادله داده ها از طریق سوکت شبکه  یااستفاده از named pipes به جای function calls . اما این گزینه ها هزینه  فدا کردن سرعت را در بر خواهند داشت.راست در مقابل Go: جمع بندیانتخاب بین Rust و Go برای یک پروژه توسعه نرم افزار عمدتا در مورد  انتخاب زبانی است که دارای کیفیتی باشد که شما برای آن پروژه بیشتر به آن  نیاز دارید. برای Rust وGo می توانید این خصوصیات را به صورت زیر جمع بندی  کنید.مزایای Rust :اصلاح در زمان اجرا (اشتباهات رایج کامپایل نمی شوند)سرعت اجرا در بالاترین سطحایمنی حافظه بدون جمع آوری زباله (یا با جمع آوری زباله آزمایشی و اختیاری از طریق پروژه های شخص ثالث)کد برای سطح سخت افزارمزایای Go:چرخه توسعه سریعسرعت اجرای بالاایمنی حافظه از طریق جمع آوری زباله (با مدیریت حافظه دستی اختیاری)راحتی توسعه دهندهکدنویسی آسان</description>
                <category>انتشارات GoLang</category>
                <author>udemyiran</author>
                <pubDate>Sat, 29 May 2021 19:41:17 +0430</pubDate>
            </item>
            </channel>
</rss>