کتابخانه‌ی استاندارد · زبان و اجرا

تزریق wire

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

واردسازی تزریق

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

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

فراهم‌کننده‌ها و بررسی گراف

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

wire-quickstart.salam
واردسازی تزریق

ساختار Repo:
    همگانی rows: صحیح = 0
پایان

ساختار Service:
    همگانی repo: Repo = Repo {}
    همگانی تابع Count(): صحیح:
        برگشت این.repo.rows
    پایان
پایان

ساختار Handler:
    همگانی svc: Service = Service {}
    همگانی تابع Serve(): رشته:
        برگشت "rows=" + این.svc.Count()
    پایان
پایان

تابع ریشه:
    c := تزریق.ساخت()
    تزریق.فراهم کردن(c، "Repo"، ""، Repo {}، (_c: تزریق.ظرف): برگشت Repo { rows = 3 } پایان)
    تزریق.فراهم کردن(c، "Service"، "Repo"، Service {}، (cx: تزریق.ظرف):
        ناپایا r := Repo {}
        _ok := تزریق.گرفتن(cx، "Repo"، r)
        برگشت Service { repo = r }
    پایان)
    تزریق.فراهم کردن(c، "Handler"، "Service"، Handler {}، (cx: تزریق.ظرف):
        ناپایا s := Service {}
        _ok := تزریق.گرفتن(cx، "Service"، s)
        برگشت Handler { svc = s }
    پایان)
    err := تزریق.ساختن گراف(c)
    اگر err نابرابر "":
        سرچاپ err
        برگشت 1
    پایان
    ناپایا h := Handler {}
    _ok := تزریق.گرفتن(c، "Handler"، h)
    سرچاپ h.Serve()
    تزریق.بستن(c)
پایان
خروجیrows=3

گرفتن جزء را در صورت نبودن می‌سازد و در خروجی کپی می‌کند. اگر نام ناشناخته باشد یا در زمان اجرا به چرخه برسد نادرست برمی‌گرداند و خطا را پر می‌کند.

میانجی، مقدار و پاکسازی

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

خواندن خطاها

ساختن گراف فقط نام‌های ثبت‌شده و فهرست نیازهایشان را نگاه می‌کند و هیچ کارخانه‌ای را اجرا نمی‌کند. گراف سالم رشته خالی می‌دهد و سه پیام دیگر این‌ها هستند: missing dependency: Service needs Repo، duplicate provider: Repo و dependency cycle: A -> B -> C -> A. آن را یک بار هنگام شروع برنامه صدا بزنید و اگر متن خالی نبود همان‌جا بایستید. گرفتن با نامی که کسی ثبت نکرده نادرست برمی‌گرداند و missing provider: Nope را در خطا می‌گذارد.

wire-guide-errors.salam
واردسازی تزریق

تابع report(label: رشته، c: تزریق.ظرف):
    msg := تزریق.ساختن گراف(c)
    سرچاپ label + ":"، msg == "" ? "sound" : msg
    تزریق.بستن(c)
پایان

تابع ریشه:
    ok := تزریق.ساخت()
    تزریق.فراهم کردن(ok، "Repo"، ""، 0، (_c: تزریق.ظرف): برگشت 1 پایان)
    report("fine"، ok)

    missing := تزریق.ساخت()
    تزریق.فراهم کردن(missing، "Service"، "Repo"، 0، (_c: تزریق.ظرف): برگشت 1 پایان)
    report("missing"، missing)

    twice := تزریق.ساخت()
    تزریق.فراهم کردن(twice، "Repo"، ""، 0، (_c: تزریق.ظرف): برگشت 1 پایان)
    تزریق.فراهم کردن(twice، "Repo"، ""، 0، (_c: تزریق.ظرف): برگشت 2 پایان)
    report("duplicate"، twice)

    loop := تزریق.ساخت()
    تزریق.فراهم کردن(loop، "A"، "B"، 0، (_c: تزریق.ظرف): برگشت 1 پایان)
    تزریق.فراهم کردن(loop، "B"، "C"، 0، (_c: تزریق.ظرف): برگشت 2 پایان)
    تزریق.فراهم کردن(loop، "C"، "A"، 0، (_c: تزریق.ظرف): برگشت 3 پایان)
    report("cycle"، loop)

    empty := تزریق.ساخت()
    ناپایا n := 0
    سرچاپ "get:"، تزریق.گرفتن(empty، "Nope"، n)، تزریق.خطا(empty)
    تزریق.بستن(empty)
پایان
خروجیfine: sound missing: missing dependency: Service needs Repo duplicate: duplicate provider: Repo cycle: dependency cycle: A -> B -> C -> A get: false missing provider: Nope

انتخاب پیاده‌سازی در محل سیم‌کشی

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

wire-guide-swap.salam
واردسازی تزریق

ساختار Config:
    همگانی env: رشته = ""
پایان

ساختار Store:
    همگانی kind: رشته = ""
پایان

تابع build(env: رشته): تزریق.ظرف:
    c := تزریق.ساخت()
    تزریق.مقدار(c، "Config"، Config { env = env })
    تزریق.فراهم کردن(c، "Mem"، ""، Store {}، (_c: تزریق.ظرف): برگشت Store { kind = "memory" } پایان)
    تزریق.فراهم کردن(c، "Disk"، "Config"، Store {}، (cx: تزریق.ظرف):
        ناپایا cfg := Config {}
        _ok := تزریق.گرفتن(cx، "Config"، cfg)
        برگشت Store { kind = "disk for " + cfg.env }
    پایان)
    اگر env == "test":
        تزریق.پیوند(c، "Store"، "Mem")
    وگرنه:
        تزریق.پیوند(c، "Store"، "Disk")
    پایان
    برگشت c
پایان

تابع ریشه:
    for_env := ["test"، "prod"]
    هر env در for_env:
        c := build(env)
        سرچاپ env + ":"، تزریق.ساختن گراف(c) == "" ? "sound" : "broken"
        ناپایا s := Store {}
        _ok := تزریق.گرفتن(c، "Store"، s)
        سرچاپ "  store is"، s.kind
        built := تزریق.ساخته شده(c)
        سرچاپ "  built"، built.طول()، "of"، تزریق.تعداد(c)
        built.آزادکن()
        تزریق.بستن(c)
    پایان
پایان
خروجیtest: sound store is memory built 1 of 4 prod: sound store is disk for prod built 2 of 4

یک بار ساختن، به ترتیب معکوس بستن

هر فراهم‌کننده تک‌نمونه است: دو بار خواستن Cache کارخانه‌اش را یک بار اجرا می‌کند و از همان مقدار دو نسخه می‌دهد. پاکسازی‌هایی که با هنگام بستن ثبت شده‌اند از آخرین جزء ساخته‌شده تا اولین اجرا می‌شوند، پس کش پیش از پایگاه داده‌ای که در دست دارد بسته می‌شود. بستن دوم کاری نمی‌کند.

wire-guide-lifecycle.salam
واردسازی تزریق

ناپایا made := 0

ساختار Db:
    همگانی id: صحیح = 0
پایان

ساختار Cache:
    همگانی db: Db = Db {}
پایان

تابع ریشه:
    c := تزریق.ساخت()
    تزریق.فراهم کردن(c، "Db"، ""، Db {}، (_c: تزریق.ظرف):
        made += 1
        برگشت Db { id = 7 }
    پایان)
    تزریق.فراهم کردن(c، "Cache"، "Db"، Cache {}، (cx: تزریق.ظرف):
        ناپایا d := Db {}
        _ok := تزریق.گرفتن(cx، "Db"، d)
        برگشت Cache { db = d }
    پایان)
    تزریق.هنگام بستن(c، "Db"، Db {}، (d: Db): سرچاپ "closing db"، d.id پایان)
    تزریق.هنگام بستن(c، "Cache"، Cache {}، (k: Cache): سرچاپ "closing cache over"، k.db.id پایان)

    before := تزریق.ساخته شده(c)
    سرچاپ "before"، before.طول()
    before.آزادکن()
    ناپایا a := Cache {}
    ناپایا b := Cache {}
    _x := تزریق.گرفتن(c، "Cache"، a)
    _y := تزریق.گرفتن(c، "Cache"، b)
    سرچاپ "factory runs"، made
    built := تزریق.ساخته شده(c)
    سرچاپ "order"، built.بگیر(0)، built.بگیر(1)
    built.آزادکن()
    تزریق.بستن(c)
    تزریق.بستن(c)
    سرچاپ "done"
پایان
خروجیbefore 0 factory runs 1 order Db Cache closing cache over 7 closing db 7 done

گونه‌ها

ظرف Container

ساختار ظرف
یک ظرف وابستگی: فراهم‌کننده‌های ثبت‌شده و اجزایی که تا اینجا ساخته شده‌اند. نسخه‌های آن وضعیت مشترک دارند.
نامانگلیسیگونهتوضیح
وضعیتstState*وضعیت مشترک ظرف.

تابع‌ها

ساخت New

تابع ساخت(): ظرف
یک ظرف خالی می‌سازد.
wire-Provide.salam
واردسازی تزریق

تابع ریشه:
    c := تزریق.ساخت()
    تزریق.فراهم کردن(c، "Base"، ""، 0، (_c: تزریق.ظرف): برگشت 10 پایان)
    تزریق.فراهم کردن(c، "Double"، "Base"، 0، (cx: تزریق.ظرف):
        ناپایا b := 0
        _ok := تزریق.گرفتن(cx، "Base"، b)
        برگشت b * 2
    پایان)
    ناپایا d := 0
    اگر تزریق.گرفتن(c، "Double"، d):
        سرچاپ d
    پایان
    تزریق.بستن(c)
پایان
خروجی20

فراهم کردن Provide

تابع فراهم کردن<T>(c: ظرف، name: رشته، needs: رشته، _witness: T، factory: تابع(ظرف): T)
فراهم‌کننده‌ای را با یک نام ثبت می‌کند. needs فهرستی از نام فراهم‌کننده‌هاست که با ویرگول جدا شده‌اند، شاهد مقداری از گونه جزء است و فقط T را مشخص می‌کند و factory جزء را می‌سازد.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: wire-Provide.salam

مقدار Value

تابع مقدار<T>(c: ظرف، name: رشته، v: T)
مقدار آماده‌ای مانند تنظیمات را با یک نام ثبت می‌کند.
wire-Value.salam
واردسازی تزریق

ساختار Config:
    همگانی port: صحیح = 0
پایان

تابع ریشه:
    c := تزریق.ساخت()
    تزریق.مقدار(c، "Config"، Config { port = 8080 })
    ناپایا cfg := Config {}
    اگر تزریق.گرفتن(c، "Config"، cfg):
        سرچاپ cfg.port
    پایان
    تزریق.بستن(c)
پایان
خروجی8080

پیوند Bind

تابع پیوند(c: ظرف، iface: رشته، concrete: رشته)
نام iface را به فراهم‌کننده concrete وصل می‌کند.
wire-Bind.salam
واردسازی تزریق

میانجی Greeter:
    تابع Hello(): رشته
پایان

ساختار English:
    همگانی تابع Hello(): رشته:
        برگشت "hello"
    پایان
پایان

تابع ریشه:
    c := تزریق.ساخت()
    تزریق.فراهم کردن(c، "English"، ""، English {}، (_c: تزریق.ظرف): برگشت English {} پایان)
    تزریق.پیوند(c، "Greeter"، "English")
    ناپایا g := English {}
    اگر تزریق.گرفتن(c، "Greeter"، g):
        سرچاپ g.Hello()
    پایان
    تزریق.بستن(c)
پایان
خروجیhello

هنگام بستن OnClose

تابع هنگام بستن<T>(c: ظرف، name: رشته، _witness: T، f: تابع(T))
پاکسازی را به یک فراهم‌کننده می‌چسباند. اگر جزء ساخته شده باشد بستن آن را صدا می‌زند.
wire-OnClose.salam
واردسازی تزریق

ساختار Conn:
    همگانی id: صحیح = 0
پایان

تابع ریشه:
    c := تزریق.ساخت()
    تزریق.فراهم کردن(c، "Conn"، ""، Conn {}، (_c: تزریق.ظرف): برگشت Conn { id = 7 } پایان)
    تزریق.هنگام بستن(c، "Conn"، Conn {}، (v: Conn): سرچاپ "closing"، v.id پایان)
    ناپایا x := Conn {}
    _ok := تزریق.گرفتن(c، "Conn"، x)
    تزریق.بستن(c)
پایان
خروجیclosing 7

ساختن گراف Build

تابع ساختن گراف(c: ظرف): رشته
گراف را بدون ساختن چیزی بررسی می‌کند. اگر سالم باشد متن خالی برمی‌گرداند و در غیر این صورت پیامی که وابستگی گم‌شده، فراهم‌کننده تکراری یا چرخه را نام می‌برد.
wire-Build.salam
واردسازی تزریق

تابع ریشه:
    c := تزریق.ساخت()
    تزریق.فراهم کردن(c، "Service"، "Repo"، 0، (_c: تزریق.ظرف): برگشت 1 پایان)
    سرچاپ تزریق.ساختن گراف(c)
    تزریق.فراهم کردن(c، "Repo"، "Service"، 0، (_c: تزریق.ظرف): برگشت 2 پایان)
    سرچاپ تزریق.ساختن گراف(c)
    تزریق.بستن(c)
پایان
خروجیmissing dependency: Service needs Repo dependency cycle: Service -> Repo -> Service

گرفتن Get

تابع گرفتن<T>(c: ظرف، name: رشته، out &: T): منطقی
اگر جزء هنوز وجود نداشته باشد آن را می‌سازد و در out کپی می‌کند. اگر نام ناشناخته باشد یا به چرخه برسد نادرست برمی‌گرداند و خطا را پر می‌کند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: wire-Provide.salam

خطا Error

تابع خطا(c: ظرف): رشته
آخرین خطای ظرف که اگر خطایی نباشد خالی است.

تعداد Count

تابع تعداد(c: ظرف): صحیح
شمار نام‌های ثبت‌شده.

ساخته شده Built

تابع ساخته شده(c: ظرف): وکتور<رشته>
نام‌هایی که ساخته شده‌اند، به ترتیب ساخته شدن.

بستن Close

تابع بستن(c: ظرف)
پاکسازی‌ها را از آخرین جزء ساخته‌شده شروع می‌کند و ظرف را آزاد می‌کند. دوبار صدا زدنش بی‌خطر است.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: wire-OnClose.salam