قابلیت go:embed به توسعهدهندگان Go اجازه میدهد فایلها و پوشههای موردنیاز برنامه را هنگام ساخت، مستقیماً در باینری نهایی قرار دهند. این ویژگی هم توزیع فایلهای ایستا را سادهتر میکند و هم دردسر خطاهای مربوط به مسیر یا جا ماندن فایلها هنگام استقرار را کاهش میدهد.
نکات کلیدی
- قابلیت go:embed از زمان انتشار Go 1.16 در سال ۲۰۲۱ در دسترس است.
- فایلها را میتوان در متغیرهای رشتهای، برش بایت یا فایلسیستم فقطخواندنی قرار داد.
- دستور go:embed شبیه توضیح کد است، اما در واقع یک دستور ویژه برای ابزارهای Go محسوب میشود.
- بسته embed باید وارد شود تا نیاز برنامه به جاسازی داده برای کامپایلر مشخص باشد.
- محتوای فایلها هنگام فرایند ساخت وارد باینری میشود، نه هنگام اجرای برنامه.
go:embed چه مسئلهای را حل میکند؟
Russ Cox و Brad Fitzpatrick این ویژگی را در سال ۲۰۲۰ طراحی کردند و go:embed یک سال بعد همراه Go 1.16 منتشر شد. هدف این بود که توسعهدهندگان بتوانند بدون تبدیل فایلها به رشتههای ثابت بدقواره یا استفاده از ابزارهای جانبی، دادهها را کنار برنامه خود قرار دهند.
برای نمونه، یک برنامه ممکن است به فایلهای HTML، CSS، JavaScript، JSON، قالبها یا اسکریپتهای پایگاه داده نیاز داشته باشد. اگر این فایلها جدا از باینری توزیع شوند، اشتباه در مسیر نسبی یا مطلق و جا ماندن یک پوشه میتواند اجرای برنامه را مختل کند. با go:embed محتوا در زمان ساخت درون برنامه قرار میگیرد و مثل یک متغیر معمولی در دسترس است.
بررسی فنی سازوکار go:embed مسیر فایلها را از درخت منبع تا مراحل ساخت، کامپایل و قرار گرفتن در باینری دنبال میکند. این مسیر نشان میدهد دستوری که در کد بسیار ساده به نظر میرسد، چگونه به ابزارهای داخلی Go متصل میشود.
سه روش استفاده از فایلهای جاسازیشده
go:embed از سه نوع داده پشتیبانی میکند: رشته، برش بایت و embed.FS. برای یک فایل متنی ساده میتوان محتوا را در رشته گذاشت؛ دادههایی مانند یک فایل SQL نیز میتوانند در برش بایت قرار بگیرند؛ و برای مجموعهای از فایلها و پوشهها، embed.FS گزینه مناسبتری است.
نوع embed.FS یک فایلسیستم فقطخواندنی ارائه میدهد و متدهای Open، ReadDir و ReadFile را در اختیار برنامه میگذارد. از آنجا که این نوع با رابط fs.FS سازگار است، میتوان آن را در بخشهایی مانند سرویسدهی فایلهای ایستا با http.FileServer یا خواندن قالبها با template.ParseFS به کار گرفت.
مسیر فایل در این فایلسیستم حفظ میشود. بنابراین اگر فایلی با مسیر assets/index.css جاسازی شده باشد، برنامه نیز باید همان مسیر را برای خواندن آن درخواست کند. الگوی assets/* فایلهای پوشه را انتخاب میکند، در حالی که مشخص کردن خود پوشه میتواند کل ساختار زیر آن را در بر بگیرد؛ البته فایلهایی که نامشان با نقطه یا زیرخط آغاز میشود، در این حالت کنار گذاشته میشوند.
چرا وارد کردن بسته embed مهم است؟
پیش از استفاده از دستور go:embed، برنامه باید بسته embed را وارد کند. اگر کد مستقیماً از نوع embed.FS استفاده کند، این بسته با نام خودش وارد میشود؛ اما زمانی که محتوا فقط در رشته یا برش بایت قرار میگیرد، میتوان از وارد کردن خالی بهشکل import _ "embed" استفاده کرد.
این وارد کردن خالی به معنای فراخوانی مستقیم یک تابع نیست. نقش آن ارسال سیگنالی به کامپایلر است تا مشخص شود برنامه به جاسازی داده نیاز دارد. سپس دستور go:embed، مسیر نسبی فایل را تعیین میکند و متغیر خط بعدی محل دسترسی برنامه به محتوای جاسازیشده خواهد بود.
نکته مهم برای شما این است که عملیات اصلی پیش از اجرای برنامه و در فرایند ساخت اتفاق میافتد. وقتی برنامه اجرا میشود، دیگر نیازی به os.Open، پیدا کردن مسیر فایل یا بررسی وجود پوشه جداگانه نیست؛ داده از قبل در باینری قرار گرفته است.
از فایل منبع تا باینری
بررسی داخلی این ویژگی مراحل مختلف ابزارهای Go را در بر میگیرد: پردازش بستهها و الگوها در go build، شناسایی دستورها و سپس رسیدگی کامپایلر به اطلاعات جاسازی. در ادامه، دادههای انتخابشده همراه کد برنامه برای ساخت خروجی نهایی آماده میشوند.
شناخت این مسیر برای استفاده عادی از go:embed ضروری نیست، اما به توسعهدهندگان کمک میکند رفتار الگوها، متغیرها و بسته embed را بهتر درک کنند. بهخصوص وقتی چند فایل، یک درخت پوشه یا فایلسیستم فقطخواندنی در برنامه دارید، دانستن اینکه هر بخش در چه مرحلهای پردازش میشود، تصمیمگیری را روشنتر میکند.
جمعبندی
go:embed راهی استاندارد و سرراست برای همراه کردن فایلهای موردنیاز با برنامههای Go است. اگر میخواهید قالبها، فایلهای ایستا یا دادههای دیگر بدون وابستگی به مسیرهای بیرونی در دسترس باشند، درک تفاوت رشته، برش بایت و embed.FS به شما کمک میکند انتخاب دقیقتری داشته باشید.