گاهی لازم است تکهای از وضعیت میان چندین «واژه» به اشتراک گذاشته شود، بدون اینکه هر بار آن را از میان اثرهای پشتهی آنها عبور دهید. متغیرهای پویای Factor، که با SYMBOL: تعریف میشوند، به هر واژه دسترسی به مقداری را میدهند که در یک فضای نام ذخیره شده است.
SYMBOL: و SYMBOLS:
SYMBOL: name یک متغیر تعریف میکند. SYMBOLS: a b c ; چند متغیر را یکجا تعریف میکند:
USING: namespaces ;
SYMBOLS: counter total ;
set-global و get-global (در namespaces) روی فضای نام سراسری کار میکنند:
set-global ( value variable -- )
get-global ( variable -- value )
change-global ( variable quot: ( old -- new ) -- )
0 counter set-global
counter get-global . ! => 0
counter [ 10 + ] change-global
counter get-global . ! => 10
برای وضعیت سطح ماژول، گونههای -global همان چیزی هستند که میخواهید.
with-variable
یک متغیر پویا گونهای دوم و محدودهمحور را هم پشتیبانی میکند. set / get / change (بدون پسوند -global) محدودهی پویای جاری را میخوانند و مینویسند، و with-variable (در namespaces) به مدت اجرای یک کوتیشن یک محدودهی تازه میسازد:
with-variable ( value variable quot -- )
set ( value variable -- )
get ( variable -- value )
change ( variable quot: ( old -- new ) -- )
تا زمانی که quot اجرا میشود، متغیر به value متصل است؛ بهمحض اینکه برگردد، اتصال از میان میرود. این کار به یک فراخوانندهی بیرونی اجازه میدهد مقداری را «تزریق» کند که کد درونی بتواند آن را بخواند، بدون اینکه آن را از میان هر امضای پشته عبور دهد.
SYMBOL: greeting
"Hello" greeting [
greeting get . ! => "Hello"
"Howdy" greeting set
greeting get . ! => "Howdy"
greeting [ "!" append ] change
greeting get . ! => "Howdy!"
] with-variable
greeting get-global . ! => f (the scoped binding is gone)
این تمرین در سراسر خود از گونهی سراسری استفاده میکند، اما شناختن خانوادهی موازی set/get/change وقتی کد دیگران را میخوانید مفید است.
ازآنجاکه متغیرهای پویا یک ارجاع را نگه میدارند، میتوانید مجموعهای تغییرپذیر را درون یکی از آنها نگه دارید و آن را در جای خود بهروزرسانی کنید:
SYMBOL: history
V{ } clone history set-global
"first event" history get-global push
"second event" history get-global push
history get-global .
! => V{ "first event" "second event" }
V{ … } یک بردار لیترال است. همیشه یک لیترال V{ } را پیش از ذخیرهکردنش clone کنید: لیترالها میان فراخوانیها به اشتراک گذاشته میشوند.
find: اولین تطابقfind (در sequences) اولین عنصری را برمیگرداند که گزاره برایش درست باشد، بههمراه اندیس آن:
find ( seq quot -- index elt/f )
اگر هیچچیز منطبق نشود، هر دو مقدار f هستند. حذف اندیس با nip و استفاده از unless* ترکیب استانداردِ «پیشفرض در صورت نبود مقدار» است.
reject: حذف موارد منطبقreject (نیز در sequences) نقطهی مقابل filter است: عناصری را برمیگرداند که در گزاره شکست میخورند.
انجمن محله از شما میخواهد ثبتنام قطعههای باغ را مدیریت کنید. وضعیت در دو متغیر پویا نگهداری میشود:
registrations — برداری از جفتهای plot که در حال حاضر به یک شخص اختصاص یافتهاند.next-id — عدد صحیحی که برای ثبتنام بعدی استفاده میشود.تاپل plot دو خانه دارد:
| خانه | نوع |
|---|---|
id |
عدد صحیح |
registered-to |
رشته |
open-garden را تعریف کنید تا متغیرهای پویا را مقداردهی اولیه کند: یک بردار خالی برای registrations و 1 برای next-id. سپس list-registrations را تعریف کنید تا بردار کنونی قطعهها را برگرداند.
open-garden
list-registrations .
! => V{ }
register را تعریف کنید تا یک اسم را از پشته بردارد، یک plot تازه با شناسهی در دسترس بعدی بسازد، آن را به بردار registrations بیفزاید، next-id را یک واحد افزایش دهد و قطعهی جدید را برگرداند.
open-garden
"Emma Balan" register .
! => T{ plot { id 1 } { registered-to "Emma Balan" } }
list-registrations .
! => V{ T{ plot { id 1 } { registered-to "Emma Balan" } } }
شناسههای قطعه باید یکتا باشند و حتی بعد از آزادسازی هم افزایش پیدا کنند. next-id هرگز نباید مقداری را دوباره استفاده کند.
release را تعریف کنید تا یک شناسه بگیرد و عنصر متناظر را از registrations حذف کند. آزاد کردن یک شناسهی ناشناخته هیچ کاری انجام نمیدهد.
open-garden
"Emma" register drop
1 release
list-registrations .
! => V{ }
get-registration را تعریف کنید تا یک شناسه بگیرد و قطعهی متناظر را برگرداند، یا اگر هیچ قطعهای آن شناسه را نداشت، نماد not-found را برگرداند.
open-garden
"Emma" register drop
1 get-registration .
! => T{ plot { id 1 } { registered-to "Emma" } }
7 get-registration .
! => not-found
find-by-name را تعریف کنید تا یک اسم بگیرد و برداری از همهی قطعههایی را برگرداند که در حال حاضر به آن شخص ثبت شدهاند.
open-garden
"Emma" register drop
"Bob" register drop
"Emma" register drop
"Emma" find-by-name .
! => V{ T{ plot { id 1 } { registered-to "Emma" } }
T{ plot { id 3 } { registered-to "Emma" } } }