Po přečtení 24.2. Místní proměnné , myslel jsem si, že deklarace proměnné var
s klíčovým slovem local
znamená, že var
„Hodnota byla přístupná pouze v rámci bloku kódu ohraničeného složenými závorkami funkce.
Po spuštění následujícího příkladu jsem však zjistil, že var
lze také přistupovat, číst a zapisovat z funkcí vyvolaných tímto blokem kódu – tj. i když je var
deklarován local
to outerFunc
, innerFunc
je stále schopen číst a měnit jeho hodnotu.
#!/usr/bin/env bash function innerFunc() { var="new value" echo "innerFunc: [var:${var}]" } function outerFunc() { local var="initial value" echo "outerFunc: before innerFunc: [var:${var}]" innerFunc echo "outerFunc: after innerFunc: [var:${var}]" } echo "global: before outerFunc: [var:${var}]" outerFunc echo "global: after outerFunc: [var:${var}]"
Výstup:
global: before outerFunc: [var:] # as expected, `var` is not accessible outside of `outerFunc` outerFunc: before innerFunc: [var:initial value] innerFunc: [var:new value] # `innerFunc` has access to `var` ?? outerFunc: after innerFunc: [var:new value] # the modification of `var` by `innerFunc` is visible to `outerFunc` ?? global: after outerFunc: [var:]
Q : Je to chyba v mém shellu (bash 4.3.42, Ubuntu 16.04, 64bit) nebo jde o očekávané chování?
EDIT: Vyřešeno. Jak poznamenal @MarkPlotnick, toto je skutečně očekávané chování.
Komentáře
Odpověď
Proměnné prostředí mají dynamický rozsah . Pokud je proměnná deklarována jako lokální pro funkci, tento obor zůstane, dokud se funkce nevrátí, a to i během volání jiných funkcí.
Existují dvě výjimky:
-
v ksh93, pokud je funkce definována se standardní
function_name () { … }
syntaxí, její místní proměnné se řídí dynamickým rozsahem. Pokud je ale funkce definována syntaxí kshfunction function_name { … }
, její lokální proměnná se řídí lexikálním / statickým rozsahem, takže nejsou viditelné v ostatních funkcích, které se tímto nazývají. -
zsh/private
autoloadable plugin vzsh
poskytujeprivate
klíčové slovo / vestavěné, které lze použít k deklaraci proměnné se statickým rozsahem.
ash, bash, pdksh a deriváty, bosh mají pouze dynamický rozsah.
Komentáře
- Mají všechny proměnné v prostředí dynamický rozsah nebo to platí pouze pro proměnné deklarované pomocí
local
? - @HaroldFischer Všechny proměnné mají dynamický rozsah. U deklarace
typeset
nebodeclare
nebolocal
je rozsah do té doby, než se funkce vrátí. Bez takové deklarace je rozsah globální. - IMHO,
If a variable is declared as local to a function, that scope remains until the function returns.
nestačí k vysvětlení toho, co je dynamický rozsah verus lexikální rozsah. Samotný popis se také použije na lexikální obor. - @jinbeomhong Ne, u lexikálního rozsahu není proměnná z funkce viditelná, zatímco tato funkce volá jinou funkci. ' Přidal jsem větu, abych to výslovně uvedl.
- Ovlivní to také volání funkcí builtins? Nebo mají vestavby vlastní rozsah?
Odpovědět
Není to chyba, volání uvnitř kontextu of the outerFunc používá tuto lokální kopii $ var. „local“ v outerFunc znamená, že globální není změněn. Pokud zavoláte innerFunc mimo externalFunc, dojde ke změně globálního $ var, ale nikoli k localFunc místní $ var. Pokud jste přidali „local“ k innerFunc, pak by se $$ – v podstatě tam budou 3 z nich:
- $ global :: var
- $ outerFunc :: var
- $ innerFunc :: var
pro použití formátu jmenného prostoru Perlu, jakýsi.
Odpověď
V function innerFunc()
nebyl var="new value"
deklarován jako místní , proto je k dispozici ve viditelném rozsahu (jednou funkce byla volána).
Naopak v function outerFunc()
byl local var="initial value"
deklarován jako místní , proto není k dispozici v globálním rozsahu (i když byla funkce volána).
Protože innerFunc()
byl nazýván jako podřízený objekt outerFunc()
, var je v místním rozsahu outerFunc()
.
man 1 bash
může pomoci objasnit
místní [volba] [název [= hodnota] …]
U každého argumentu místní je vytvořena proměnná s názvem a je jí přiřazena hodnota. Možnost může být kterákoli z možností přijatých deklarací.Když se ve funkci používá local, způsobí to, že název proměnné má viditelný rozsah omezený na tuto funkci a její podřízené objekty. …
Implicitní chování, kterého se v popisu očekává, lze dosáhnout deklarováním local var="new value
v function innerFunc()
.
Jak uvedli jiní, nejedná se o chybu v prostředí bash. Všechno funguje tak, jak má.
Komentáře
- Vaše první prohlášení je v rozporu s tím, co uživatel vidí. Tisk hodnoty
var
v globálním rozsahu po voláníinnerFunc
prostřednictvímoutFunc
se netisknoutnew value
.
odpověď
Můžete použít funkce vynutit místní obor:
sh_local() { eval "$(set)" command eval "\"\$@\"" }
Příklad:
x() { z="new value" printf "function x, z = [%s]\n" "$z" } y() { z="initial value" printf "function y before x, z = [%s]\n" "$z" sh_local x printf "function y after x, z = [%s]\n" "$z" } printf "global before y, z = [%s]\n" "$z" y printf "global after y, z = [%s]\n" "$z"
Výsledek:
global before y, z = [] function y before x, z = [initial value] function x, z = [new value] function y after x, z = [initial value] global after y, z = [initial value]
var
prázdná?var
je globálně nastaven nainnerFunc
, tak proč se ' nelepí až do konce skriptu?