Paikallisten muuttujien laajuus kuoritoiminnoissa

Luettuasi 24.2. Paikalliset muuttujat , ajattelin, että muuttujan var ilmoittaminen avainsanalla local tarkoitti sitä, että var ”: n arvo oli käytettävissä vain koodilohkossa, jonka rajaavat funktion kiharat aaltosulkeet.

Seuraavan esimerkin suorittamisen jälkeen sain kuitenkin selville, että var voidaan käyttää, lukea ja kirjoittaa myös toiminnoista, joihin kyseinen koodilohko on kutsunut – vaikka var on ilmoitettu localouterFunc, innerFunc pystyy edelleen lukemaan sen ja muuttamaan sen arvoa.

Suorita se verkossa

#!/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}]" 

Tulos:

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 : Onko se vika kuoressani (bash 4.3.42, Ubuntu 16.04, 64bit) vai onko se odotettua käyttäytymistä?

MUOKKAA: Ratkaistu. Kuten @MarkPlotnick huomautti, tämä on todellakin odotettua käyttäytymistä.

Kommentit

  • Se on odotettua käyttäytymistä
  • Olenko minä Ainoa, joka ajattelee ' on outoa, että viimeisellä tulosrivillä var arvo on tyhjä? var on asetettu globaalisti kohtaan innerFunc, joten miksi ' ei se tartu loppuun asti komentosarjan?

vastaus

Shell-muuttujilla on dynaaminen laajuus . Jos muuttuja ilmoitetaan paikalliseksi funktiolle, kyseinen laajuus pysyy, kunnes funktio palaa, mukaan lukien muihin toimintoihin soitettujen puheluiden aikana.

On olemassa kaksi poikkeusta:

  1. ksh93: ssä, jos funktio määritetään vakiosyntaksilla function_name () { … }, sen paikalliset muuttujat noudattavat dynaamista laajuutta. Mutta jos funktio määritetään ksh-syntaksilla function function_name { … }, sen paikallinen muuttuja noudattaa leksikaalista / staattista ulottuvuutta, joten ne eivät ole näkyvissä muissa tällä kutsumissa funktioissa.

  2. zsh/private automaattisesti ladattava laajennus zsh sisältää private avainsana / sisäänrakennettu, jota voidaan käyttää staattisen laajuuden muuttujan ilmoittamiseen.

ash, bash, pdksh ja johdannaiset, boshilla on vain dynaaminen ulottuvuus.

Kommentit

  • Onko kaikilla kuoren muuttujilla dynaaminen laajuus vai koskeeko tämä vain muuttujia, jotka on ilmoitettu merkinnällä local?
  • @HaroldFischer Kaikilla muuttujilla on dynaaminen laajuus. typeset – tai declare – tai local -lausekkeen kanssa soveltamisala on, kunnes funktio palaa. Ilman tällaista ilmoitusta soveltamisala on globaali.
  • IMHO, If a variable is declared as local to a function, that scope remains until the function returns. ei riitä selittämään, mikä on dynaaminen laajuus verus leksikaalinen. Pelkästään kuvausta sovelletaan myös leksikaaliseen laajuuteen.
  • @jinbeomhong Ei, leksikaalisen laajuuden mukaan funktion muuttuja ei ole näkyvissä, kun taas tämä funktio kutsuu toista toimintoa. Olen ' lisännyt lauseen ilmaisemaan tämän nimenomaisesti.
  • Vaikuttaako tämä myös sisäänrakennuksia kutsuviin funktioihin? Vai onko sisäänrakennetuilla laitteilla oma soveltamisala?

Vastaa

Se ei ole virhe, puhelu kontekstissa of externalFunc käyttää sitä $ var: n paikallista kopiota. ”local” osiossa externalFunc tarkoittaa, että globaalia ei muuteta. Jos kutsut sisäistä funktiota ulkoisen funktion ulkopuolelle, muutos globaaliin $ var: iin tapahtuu, mutta ei ulkoisenFunc: n paikalliseen $ variin. Jos lisääit ”local”: n sisäiseen funktioon, ulkoisen funktion ”s $ var” ei muutu – Pohjimmiltaan heitä on 3:

  • $ global :: var
  • $ externalFunc :: var
  • $ innerFunc :: var

käyttää Perlin nimiavaruusmuotoa, eräänlainen.

Vastaa

Kohdassa function innerFunc() var="new value" ei ilmoitettu paikalliseksi , joten se on käytettävissä näkyvissä (kerran toimintoa on kutsuttu).

Käänteisesti function outerFunc() -kohdassa local var="initial value" julistettiin paikalliseksi , joten se ei ole käytettävissä maailmanlaajuisesti (vaikka toimintoa olisi kutsuttu).

Koska innerFunc() kutsuttiin outerFunc(), var on outerFunc() -alueen laajuudessa.

man 1 bash voi auttaa selventämään

paikallinen [vaihtoehto] [nimi [= arvo] …]

Jokaiselle argumentille paikallinen muuttuja nimeltä nimi luodaan ja määritetään arvo. Vaihtoehto voi olla mikä tahansa julistuksen hyväksymästä vaihtoehdosta.Kun funktiossa käytetään paikallista, se saa muuttujan nimen näkyväksi vain funktiolle ja sen lapsille. …

Epäsuora käyttäytyminen, jonka kuvauksessa odotetaan, voidaan saavuttaa ilmoittamalla local var="new value function innerFunc().

Kuten muut ovat todenneet, tämä ei ole vika bash-kuoressa. Kaikki toimii kuten pitäisi.

Kommentit

  • Ensimmäinen lauseesi on ristiriidassa käyttäjän näkemien asioiden kanssa. var -arvon tulostaminen globaalissa laajuudessa, kun innerFunc on kutsuttu outFunc -palvelun kautta ei tulosta new value.

Vastaa

Voit käyttää toiminto pakottaa paikallinen laajuus:

sh_local() { eval "$(set)" command eval "\"\$@\"" } 

Esimerkki:

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" 

Tulos:

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] 

Lähde

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *