Rozsah místních proměnných ve funkcích prostředí

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.

Spustit online

#!/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

  • Jedná se o očekávané chování
  • Jsem jediný, kdo si myslí, že je ' divné, že na posledním řádku výstupu je hodnota var prázdná? var je globálně nastaven na innerFunc, tak proč se ' nelepí až do konce skriptu?

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:

  1. 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í ksh function 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í.

  2. zsh/private autoloadable plugin v zsh poskytuje private 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 nebo declare nebo local 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ím outFunc se netisknout new 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] 

Zdroj

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *