Jawaban:
Dalam Lua 5.2 solusi terbaik adalah menggunakan goto:
-- prints odd numbers in [|1,10|]
for i=1,10 do
if i % 2 == 0 then goto continue end
print(i)
::continue::
end
Ini didukung di LuaJIT sejak versi 2.0.1
continue
. The goto
pengganti tidak terlihat sangat bagus dan membutuhkan lebih banyak garis. Juga, bukankah itu akan menimbulkan masalah jika Anda memiliki lebih dari satu loop melakukan ini dalam satu fungsi, keduanya dengan ::continue::
? Membuat nama per loop tidak terdengar seperti hal yang layak untuk dilakukan.
Cara bahasa mengelola ruang lingkup leksikal menciptakan masalah dengan menyertakan keduanya goto
dan continue
. Sebagai contoh,
local a=0
repeat
if f() then
a=1 --change outer a
end
local a=f() -- inner a
until a==0 -- test inner a
Deklarasi local a
di dalam loop body menutupi variabel luar bernama a
, dan cakupan lokal itu meluas di seluruh kondisi until
pernyataan sehingga kondisi sedang menguji yang paling dalam a
.
Jika continue
ada, itu harus dibatasi secara semantik hanya valid setelah semua variabel yang digunakan dalam kondisi tersebut masuk ke dalam ruang lingkup. Ini adalah kondisi yang sulit untuk didokumentasikan kepada pengguna dan ditegakkan dalam kompiler. Berbagai proposal seputar masalah ini telah dibahas, termasuk jawaban sederhana penolakan continue
dengan repeat ... until
gaya loop. Sejauh ini, tidak ada yang memiliki kasus penggunaan yang cukup menarik untuk memasukkan mereka ke dalam bahasa.
Pekerjaan sekitar umumnya untuk membalikkan kondisi yang akan menyebabkan a continue
dieksekusi, dan mengumpulkan sisa tubuh loop di bawah kondisi itu. Jadi, loop berikut
-- not valid Lua 5.1 (or 5.2)
for k,v in pairs(t) do
if isstring(k) then continue end
-- do something to t[k] when k is not a string
end
dapat ditulis
-- valid Lua 5.1 (or 5.2)
for k,v in pairs(t) do
if not isstring(k) then
-- do something to t[k] when k is not a string
end
end
Ini cukup jelas, dan biasanya bukan beban kecuali Anda memiliki serangkaian pemusnahan rumit yang mengontrol operasi loop.
until...
.
goto
ke dalam Lua 5.2. Secara alami, goto
memiliki masalah yang sama. Mereka akhirnya memutuskan bahwa apa pun biaya runtime dan / atau pembuatan kode untuk melindunginya tidak sepadan dengan manfaat memiliki fleksibel goto
yang dapat digunakan untuk meniru keduanya continue
dan multi-level break
. Anda harus mencari arsip daftar Lua untuk utas yang relevan untuk mendapatkan detailnya. Karena mereka memang memperkenalkan goto
, itu jelas tidak dapat diatasi.
local
adalah arahan hanya kompiler - tidak peduli apa pun runtime insructions berada di antara local
dan penggunaan variabel - Anda tidak perlu mengubah apa pun di kompiler untuk mempertahankan perilaku pelingkupan yang sama. Ya, ini mungkin tidak begitu jelas dan memerlukan beberapa dokumentasi tambahan, tetapi, untuk mengulangi lagi, diperlukan perubahan NOL dalam kompiler. repeat do break end until true
contoh dalam jawaban saya sudah menghasilkan bytecode yang sama persis bahwa compiler akan melanjutkan, satu-satunya perbedaan adalah bahwa dengan continue
Anda tidak perlu sintaks tambahan yang jelek untuk menggunakannya.
do{int i=0;}while (i == 0);
gagal, atau dalam C ++: do int i=0;while (i==0);
juga gagal ("tidak dideklarasikan dalam lingkup ini"). Terlambat untuk mengubahnya sekarang di Lua, sayangnya.
Anda dapat membungkus lingkaran tubuh di tambahan repeat until true
dan kemudian gunakan do break end
di dalam untuk efek melanjutkan. Secara alami, Anda perlu mengatur flag tambahan jika Anda juga bermaksud untuk benar-benar break
keluar dari loop.
Ini akan berulang 5 kali, mencetak 1, 2, dan 3 setiap kali.
for idx = 1, 5 do
repeat
print(1)
print(2)
print(3)
do break end -- goes to next iteration of for
print(4)
print(5)
until true
end
Konstruksi ini bahkan diterjemahkan menjadi opcode literal JMP
dalam bytecode Lua!
$ luac -l continue.lua
main <continue.lua:0,0> (22 instructions, 88 bytes at 0x23c9530)
0+ params, 6 slots, 0 upvalues, 4 locals, 6 constants, 0 functions
1 [1] LOADK 0 -1 ; 1
2 [1] LOADK 1 -2 ; 3
3 [1] LOADK 2 -1 ; 1
4 [1] FORPREP 0 16 ; to 21
5 [3] GETGLOBAL 4 -3 ; print
6 [3] LOADK 5 -1 ; 1
7 [3] CALL 4 2 1
8 [4] GETGLOBAL 4 -3 ; print
9 [4] LOADK 5 -4 ; 2
10 [4] CALL 4 2 1
11 [5] GETGLOBAL 4 -3 ; print
12 [5] LOADK 5 -2 ; 3
13 [5] CALL 4 2 1
14 [6] JMP 6 ; to 21 -- Here it is! If you remove do break end from code, result will only differ by this single line.
15 [7] GETGLOBAL 4 -3 ; print
16 [7] LOADK 5 -5 ; 4
17 [7] CALL 4 2 1
18 [8] GETGLOBAL 4 -3 ; print
19 [8] LOADK 5 -6 ; 5
20 [8] CALL 4 2 1
21 [1] FORLOOP 0 -17 ; to 5
22 [10] RETURN 0 1
luac
output pada SO! Selamat menikmati :):
Langsung dari desainer Lua sendiri :
Perhatian utama kami dengan "melanjutkan" adalah bahwa ada beberapa struktur kontrol lain yang (dalam pandangan kami) lebih atau kurang sama pentingnya dengan "melanjutkan" dan bahkan mungkin menggantinya. (Misalnya, putus dengan label [seperti di Jawa] atau bahkan goto yang lebih umum.) "Terus" tampaknya tidak lebih istimewa daripada mekanisme struktur kontrol lainnya, kecuali bahwa ia hadir dalam lebih banyak bahasa. (Perl sebenarnya memiliki dua pernyataan "lanjutkan", "berikutnya" dan "ulang". Keduanya berguna.)
continue
ke dalam Lua, maaf."
Bagian pertama dijawab di FAQ sebagai dibunuh keluar runcing.
Adapun solusinya, Anda bisa membungkus tubuh loop dalam suatu fungsi dan return
awal dari itu, misalnya
-- Print the odd numbers from 1 to 99
for a = 1, 99 do
(function()
if a % 2 == 0 then
return
end
print(a)
end)()
end
Atau jika Anda ingin keduanya break
dan continue
fungsionalitas, mintalah fungsi lokal melakukan tes, mis
local a = 1
while (function()
if a > 99 then
return false; -- break
end
if a % 2 == 0 then
return true; -- continue
end
print(a)
return true; -- continue
end)() do
a = a + 1
end
collectgarbage("count")
bahkan setelah 100 percobaan sederhana Anda dan kemudian kami akan berbicara. Optimalisasi "prematur" seperti itu menyelamatkan satu proyek highload dari reboot setiap menit minggu lalu.
Saya belum pernah menggunakan Lua sebelumnya, tetapi saya mencari di Google dan menghasilkan ini:
Periksa pertanyaan 1.26 .
Ini adalah keluhan umum. Para penulis Lua merasa bahwa terus hanyalah salah satu dari sejumlah mekanisme aliran kontrol baru yang mungkin (fakta bahwa ia tidak dapat bekerja dengan aturan lingkup pengulangan / sampai adalah faktor sekunder.)
Dalam Lua 5.2, ada pernyataan goto yang dapat dengan mudah digunakan untuk melakukan pekerjaan yang sama.
Kami mengalami skenario ini berkali-kali dan kami hanya menggunakan bendera untuk mensimulasikan melanjutkan. Kami mencoba untuk menghindari penggunaan pernyataan goto juga.
Contoh: Kode ini bermaksud untuk mencetak pernyataan dari i = 1 ke i = 10 kecuali i = 3. Selain itu ia juga mencetak "loop start", loop end "," if start ", dan" if end "untuk mensimulasikan pernyataan bersarang lainnya yang ada dalam kode Anda.
size = 10
for i=1, size do
print("loop start")
if whatever then
print("if start")
if (i == 3) then
print("i is 3")
--continue
end
print(j)
print("if end")
end
print("loop end")
end
dicapai dengan melampirkan semua pernyataan yang tersisa sampai ruang lingkup akhir loop dengan bendera tes.
size = 10
for i=1, size do
print("loop start")
local continue = false; -- initialize flag at the start of the loop
if whatever then
print("if start")
if (i == 3) then
print("i is 3")
continue = true
end
if continue==false then -- test flag
print(j)
print("if end")
end
end
if (continue==false) then -- test flag
print("loop end")
end
end
Saya tidak mengatakan bahwa ini adalah pendekatan terbaik tetapi itu bekerja dengan baik bagi kami.
Lua adalah bahasa scripting ringan yang ingin mengecil mungkin. Misalnya, banyak operasi unary seperti kenaikan sebelum / sesudah tidak tersedia
Alih-alih melanjutkan, Anda bisa menggunakan goto like
arr = {1,2,3,45,6,7,8}
for key,val in ipairs(arr) do
if val > 6 then
goto skip_to_next
end
# perform some calculation
::skip_to_next::
end
Sekali lagi dengan pembalik, Anda cukup menggunakan kode berikut:
for k,v in pairs(t) do
if not isstring(k) then
-- do something to t[k] when k is not a string
end
Karena itu tidak perlu¹. Ada beberapa situasi di mana seorang dev akan membutuhkannya.
A) Ketika Anda memiliki loop yang sangat sederhana, katakanlah 1 atau 2-liner, maka Anda bisa membalikkan kondisi loop dan masih banyak yang bisa dibaca.
B) Ketika Anda menulis kode prosedural sederhana (alias. Bagaimana kami menulis kode pada abad terakhir), Anda juga harus menerapkan pemrograman terstruktur (alias. Bagaimana kami menulis kode yang lebih baik pada abad terakhir)
C) Jika Anda menulis kode berorientasi objek, badan loop Anda harus terdiri dari tidak lebih dari satu atau dua pemanggilan metode kecuali dapat dinyatakan dalam satu atau dua-liner (dalam hal ini, lihat A)
D) Jika Anda menulis kode fungsional, cukup kembalikan panggilan ekor untuk iterasi berikutnya.
Satu-satunya kasus ketika Anda ingin menggunakan continue
kata kunci adalah jika Anda ingin kode Lua seperti itu python, padahal tidak .²
Kecuali A) berlaku, dalam hal ini tidak perlu ada solusi, Anda harus melakukan pemrograman Terstruktur, Berorientasi Objek atau Fungsional. Itulah paradigma yang dibangun Lua, jadi Anda akan berjuang melawan bahasa jika Anda berusaha keras untuk menghindari pola mereka. Their
Beberapa klarifikasi:
¹ Lua adalah bahasa yang sangat minimalis. Itu mencoba untuk memiliki fitur sesedikit mungkin, dan continue
pernyataan bukanlah fitur penting dalam arti itu.
Saya pikir filosofi minimalis ini ditangkap dengan baik oleh Roberto Ierusalimschy dalam wawancara tahun 2019 ini :
tambahkan itu dan itu dan itu, keluarkan itu, dan pada akhirnya kita memahami kesimpulan akhir tidak akan memuaskan kebanyakan orang dan kita tidak akan menempatkan semua opsi yang diinginkan semua orang, jadi kita tidak menaruh apa pun. Pada akhirnya, mode ketat adalah kompromi yang masuk akal.
² Tampaknya ada sejumlah besar programmer yang datang ke Lua dari bahasa lain karena program apa pun yang mereka coba skrip untuk menggunakannya, dan banyak dari mereka sepertinya tidak ingin menulis apa pun selain bahasa mereka sendiri. pilihan, yang mengarah ke banyak pertanyaan seperti "Mengapa Lua tidak memiliki fitur X?"
Matz menggambarkan situasi yang sama dengan Ruby dalam sebuah wawancara baru - baru ini :
Pertanyaan paling populer adalah: "Saya dari komunitas bahasa X; tidak bisakah Anda memperkenalkan fitur dari bahasa X ke Ruby?", Atau sesuatu seperti itu. Dan jawaban saya yang biasa untuk permintaan ini adalah ... "tidak, saya tidak akan melakukan itu", karena kami memiliki desain bahasa yang berbeda dan kebijakan pengembangan bahasa yang berbeda.
³ Ada beberapa cara untuk meretas jalan Anda di sekitar ini; beberapa pengguna telah menyarankan untuk menggunakan goto
, yang merupakan aproximation cukup baik dalam kebanyakan kasus, tetapi menjadi sangat jelek dengan sangat cepat dan benar-benar rusak dengan loop bersarang. Menggunakan goto
s juga menempatkan Anda dalam bahaya memiliki salinan SICP yang dilemparkan kepada Anda setiap kali Anda menunjukkan kode Anda kepada orang lain.
continue
mungkin fitur yang nyaman, tetapi itu tidak membuatnya perlu . Banyak orang menggunakan Lua baik-baik saja tanpa itu, jadi benar-benar tidak ada kasus untuk itu selain fitur rapi yang tidak penting untuk bahasa pemrograman apa pun.
goto
pernyataan yang dapat digunakan untuk mengimplementasikan melanjutkan. Lihat jawabannya di bawah.