După citirea 24.2. Variabile locale , am crezut că declararea unei variabile var
cu cuvântul cheie local
înseamnă că var
„Valoarea era accesibilă numai în blocul de cod delimitat de acoladele unei funcții.
Cu toate acestea, după ce am rulat următorul exemplu, am aflat că var
poate fi accesat, citit și scris și din funcțiile invocate de acel bloc de cod – adică chiar dacă var
este declarat local
la outerFunc
, innerFunc
este în continuare capabil să-l citească și să-i modifice valoarea.
#!/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}]"
Ieșire:
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 : Este o eroare în shell-ul meu (bash 4.3.42, Ubuntu 16.04, 64bit) sau este comportamentul așteptat?
EDIT: Rezolvat. După cum a menționat @MarkPlotnick, acesta este într-adevăr comportamentul așteptat.
Comentarii
Răspuns
Variabilele Shell au un domeniu dinamic . Dacă o variabilă este declarată locală pentru o funcție, domeniul respectiv rămâne până când funcția revine, inclusiv în timpul apelurilor către alte funcții.
Există două excepții:
-
în ksh93, dacă o funcție este definită cu sintaxa standard
function_name () { … }
, variabilele sale locale respectă sfera dinamică. Dar dacă o funcție este definită cu sintaxa kshfunction function_name { … }
, atunci variabila sa locală respectă sfera lexicală / statică, deci nu sunt vizibile în alte funcții numite de aceasta. -
zsh/private
pluginul autoîncărcabil dinzsh
oferă unprivate
cuvânt cheie / încorporat care poate fi utilizat pentru a declara o variabilă cu scop static.
cenușă, bash, pdksh și derivate, bosh are doar scop dinamic.
Comentarii
- Toate variabilele din shell au un domeniu dinamic sau se aplică acest lucru numai variabilelor declarate cu
local
? - @HaroldFischer Toate variabilele au domeniu dinamic. Cu o declarație
typeset
saudeclare
saulocal
, domeniul de aplicare este până când funcția revine. Fără o astfel de declarație, domeniul de aplicare este global. - IMHO,
If a variable is declared as local to a function, that scope remains until the function returns.
nu este suficient pentru a explica ce este domeniul de aplicare dinamic verus domeniul de aplicare lexical. Numai descrierea se aplică și domeniului lexical. - @jinbeomhong Nu, cu domeniul lexical, o variabilă dintr-o funcție nu este vizibilă în timp ce această funcție apelează o altă funcție. Am ' am adăugat o propoziție pentru a afirma acest lucru în mod explicit.
- Afectează acest lucru și funcțiile integrate de apelare a funcțiilor? Sau încorporatele au propriul lor domeniu de aplicare?
Răspuns
Nu este „o eroare, apelul din context din externalFunc folosește acea copie locală a lui $ var. „Local” din externalFunc înseamnă că globalul nu este modificat. Dacă apelați innerFunc în afara externalFunc, atunci va exista o schimbare la $ var global, dar nu și $ var local la externalFunc. Dacă ați adăugat „local” la innerFunc, atunci $ var externalFunc nu ar putea fi modificat – în esență, ar fi 3 dintre ele:
- $ global :: var
- $ outerFunc :: var
- $ innerFunc :: var
pentru a utiliza formatul spațiului de nume al Perl, un fel de.
Răspuns
În function innerFunc()
var="new value"
nu a fost declarat ca local , prin urmare este disponibil în domeniul vizibil (o dată funcția a fost numită).
În schimb, în function outerFunc()
local var="initial value"
a fost declarat ca local , prin urmare nu este disponibil în domeniul global (chiar dacă funcția a fost apelată).
Deoarece innerFunc()
a fost chemat ca un copil al outerFunc()
, var se încadrează în domeniul local al outerFunc()
.
man 1 bash
poate ajuta la clarificarea
local [opțiune] [nume [= valoare] …]
Pentru fiecare argument, un local se creează numele variabilei denumite și i se atribuie valoarea. Opțiunea poate fi oricare dintre opțiunile acceptate prin declare.Când localul este utilizat într-o funcție, aceasta face ca numele variabilei să aibă un domeniu vizibil limitat la acea funcție și la copiii săi. …
Comportamentul implicit pe care îl așteptați în descriere ar putea fi realizat prin declararea local var="new value
în function innerFunc()
.
După cum au afirmat alții, aceasta nu este o eroare în shell-ul bash. Totul funcționează așa cum ar trebui.
Comentarii
- Prima dvs. afirmație contrazice ceea ce vede utilizatorul. Imprimarea valorii
var
în domeniul global, după apelareainnerFunc
prinoutFunc
, nu not printnew value
.
Răspuns
Puteți utiliza un funcție pentru a forța domeniul de aplicare local:
sh_local() { eval "$(set)" command eval "\"\$@\"" }
Exemplu:
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"
Rezultat:
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
este goală?var
este setat global îninnerFunc
, deci de ce nu ' rămâne până la sfârșit a scriptului?