Gawk: Melewati array ke fungsi

9

Terjebak dengan GNU awk 3.1.6 dan berpikir saya telah mengatasi bug array-nya tetapi masih memiliki apa yang tampak seperti masalah cakupan dalam program awk 600-baris. Perlu memverifikasi pemahaman tentang ruang lingkup array di awk untuk menemukan bug saya.

Diberikan kode awk ilustratif ini ...

function foo(ga) {
  ga[1] = "global result"
}

garray[1] = "global"
foo(garray)

print garray[1]

akan mencetak ...

global result

Karena array selalu diteruskan ke fungsi dengan referensi, maka semua array selalu global. Tidak ada cara untuk membuat array lokal. Apakah ini benar? Tidak dapat menemukan dokumen yang secara eksplisit mengatakan itu.

Karena saya sedang men-debug, dan 3.1.6 sendiri memiliki bug di area ini, saya mencoba menentukan di mana bug awk pergi dan saya mulai.

Tambahan: Mengapa ga [] bekerja di dalam fungsi?

Pertama-tama, meneruskan array ke fungsi dengan foo(ga)sebenarnya tidak perlu. Akses saja seperti garray[]di dalam fungsi. Namun, tidak ada penalti kinerja yang dapat diukur, dan ini membantu dalam debugging dan pelaporan kesalahan.

Dalam menggunakan foo(ga), ga[]adalah sinonim untuk array global garray[]. Alih-alih menjadi salinan lokal garray[], itu hanya sebuah penunjuk garray[], bukan seperti tautan simbolis adalah penunjuk ke file dan dengan demikian file yang sama (atau array) dapat diakses dengan lebih dari satu nama.

Tambahan: Klarifikasi jawaban Glenn Jackman

Sementara array yang dibuat di luar fungsi bersifat global ke fungsi dan dapat diteruskan ke atau hanya direferensikan di dalamnya, array yang dibuat di dalam suatu fungsi memang tetap lokal pada fungsi dan tidak terlihat di luarnya. Memodifikasi contoh Mr. Jackman menggambarkan ini ...

awk '
    function bar(x,y) {
      split("hello world", y)
      print "x[1] inside: " x[1]
      print "y[1] inside: " y[1]
    }
    BEGIN {
      x[1]="goodbye"
      print "x[1] before: " x[1]
      print "y[1] before: " y[1]
      bar(x)
      print "x[1] after: " x[1]
      print "y[1] after: " y[1]
    }
'
x[1] before: goodbye
y[1] before: 
x[1] inside: goodbye
y[1] inside: hello
x[1] after: goodbye
y[1] after: 

Perhatikan bahwa kita hanya meneruskan x[]array (sebenarnya, hanya sebuah pointer ke sana) ke bar(). The y[]Array bahkan tidak ada sampai kita masuk ke dalam fungsi.

Namun, jika kita mendeklarasikan y[]dengan memasukkannya ke dalam bar()daftar argumen tanpa menetapkan apa pun di luar fungsi, itu akan terlihat setelah memanggil bar(x,y)...

awk '
    function bar(x,y) {
      split("hello world", y)
      print "x[1] inside: " x[1]
      print "y[1] inside: " y[1]
    }
    BEGIN {
      x[1]="goodbye"
      print "x[1] before: " x[1]
      print "y[1] before: " y[1]
      bar(x,y)
      print "x[1] after: " x[1]
      print "y[1] after: " y[1]
    }
'
x[1] before: goodbye
y[1] before: 
x[1] inside: goodbye
y[1] inside: hello
x[1] after: goodbye
y[1] after: hello

Akhirnya, jika kita membuat y[]array di luar fungsi dan meneruskannya bar(x,y), split()tugas di dalam fungsi menggantikan elemen array itu ...

awk '
    function bar(x,y) {
      split("hello world", y)
      print "x[1] inside: " x[1]
      print "y[1] inside: " y[1]
    }
    BEGIN {
      x[1]="goodbye"
      y[1]="howdy"
      print "x[1] before: " x[1]
      print "y[1] before: " y[1]
      bar(x,y)
      print "x[1] after: " x[1]
      print "y[1] after: " y[1]
    }
'
x[1] before: goodbye
y[1] before: howdy
x[1] inside: goodbye
y[1] inside: hello
x[1] after: goodbye
y[1] after: hello
DocSalvager
sumber

Jawaban:

5

Parameter fungsi bersifat lokal untuk fungsi tersebut.

awk '
    function foo(x,y) {y=x*x; print "y in function: "y} 
    BEGIN {foo(2); print "y out of function: " y}
'
y in function: 4
y out of function: 

Jika Anda memberikan nilai lebih sedikit ke fungsi daripada parameter, parameter tambahan hanya kosong. Terkadang Anda mungkin melihat fungsi yang didefinisikan seperti

function foo(a, b, c            d, e, f) {...

di mana parameter setelah spasi putih adalah variabel lokal dan tidak dimaksudkan untuk mengambil nilai saat doa.

Tidak ada alasan mengapa ini tidak berfungsi untuk array lokal:

awk '
    function bar(x) {
        split("hello world", x)
        print "in: " x[1]
    }
    BEGIN {
        x[1]="world"
        bar()
        print "out: " x[1]}
'
in: hello
out: world
glenn jackman
sumber
3

The dokumentasi melongo membuatnya jelas bahwa array dikirimkan dengan referensi, dan ada yang tidak terdokumentasi jalan di sekitar itu. Perilaku ini sama dengan gawk4.0.1.

POSIX menentukan perilaku itu , jadi saya tidak berharap Anda akan menemukan awkimplementasi yang berperilaku sebaliknya.

Jika Anda membutuhkan fungsionalitas itu, Anda bisa menggunakannya perl. perldilengkapi dengan alat ( a2p) untuk menerjemahkan awkskrip ke perl.

Stéphane Chazelas
sumber