break、return和goto

break、return 和 goto

    break和return語句用於從當前的循環結構中跳出,goto語句則允許跳轉到函數中的幾乎任何地方。
    我們可以使用break語句結束循環,該語句會中斷包含它的內層循環;該語句不能在循環外使用。break中斷後,程序會緊接着被中斷的循環繼續執行。
    return語句用於返回函數的執行結果或簡單地結束函數的運行。所有函數的最後都有一個隱含的return,因此我們不需要在每一個沒有返還值的函數最後書寫return語句。
    按照這個語法,return只能是代碼塊中的最後一句:換句話說,它只能是代碼塊的最後一句,或者是end、else和until之前的最後一句。例如,在下面的例子中,return是then代碼塊的最後一句:

local i = 1
while a[i] do
	if a[i] == v then return i end
	i = i + 1
end

通常,這些地方正是使用return的典型位置,return之後的語句不會被執行。不過,有時再代碼塊中間使用return也是很有用你的。列如,在調試我們可能不想讓某個函數執行。在這種情況下,可以顯示地使用一個包含break的do:

function foo()
	return
	do return end
	other statements
end

    goto語句用於將當前程序跳轉到相應的標籤出繼續執行。goto語句一直以來備受爭議,至今仍有很多人認爲它們不利於程序開發並且應該在變成語言中禁止。不過儘管如此,仍有很多語言處於很多原因保留了goto語句。goto語句有很強大的功能,只要足夠細心,我們就能夠利用它來提高代碼質量。
    在lua語言中,goto語句的語法非常傳統,既保留字goto後面緊跟着標籤名,標籤名可以是人以有效的標識符。標籤的語法稍微有點複雜:標籤名稱前後各緊跟兩個冒號,形如::name::。這個複雜的語法是有意而爲的,主要是爲了在程序中醒目地突出這些標籤。
    在使用goto跳轉時,Lua語言設置了一些限制條件。首先,標籤遵循常見的可見性規則,因此不能直接跳轉到一個代碼塊中的標籤。其次,goto不能跳轉到函數外。最後,goto不能跳轉到局部變量的作用域。
    關於goto語句典型且正確的使用方式,請參考其他一些編程語言中存在但Lua語言中不存在的代碼結構,例如continue、多級break、多級continue、redo和局部錯誤處理等。continue語句僅僅相當於一個跳轉到位於循環體最後位置處標籤的goto語句,而redo語句則相當於跳轉到代碼塊開始位置的goto語句:

while some_condition do
	::redo::
	if some_other_condition then goto continue
	else if yet_another_condition then goto redo
	end
	some code 
	::continue::
end

    Lua語言規範中一個很有用的細節是,局部變量的作用域終止於聲明變量的代碼塊中的最後一個有效語句處,標籤被認爲是無效語句。下列代碼展示了這個使用的細節:

while some_condition do 
	if some_other_condition then goto continue end
	local var = something
	::continue::
end

讀者可能認爲,這個goto語句跳轉到了變量var的作用域內。但實際上這個continue標籤出現在該代碼塊的最後一個有效語句後,因此goto並未跳轉進入變量var的作用域內。
    goto語句在編寫狀態機時也很有用。

-- 一個使用goto語句的狀態機的示例
::s1:: do 
	local c = io.read(1)
	if c == '0' then goto s2
	elseif c == nil then print 'ok'; return
	else goto s1
	end
end

::s2:: do
	local c = io.read(1)
	if c == '0' then goto s1
	elseif c == nil then print'not ok'; return
	else goto s2
	end
end

goto s1

    雖然可以使用更好的方式來編寫這段代碼,但上例中的方法有助於將一個有限自動機自動地轉化爲Lua語言代碼。
    再舉一個簡單的迷宮遊戲的例子。迷宮中有幾個房間,每個房間的東南西北向各有一扇門。玩家每次可以出入移動的方向,如果在這個方向上有一扇門,則玩家可以進入相應的房間,否則程序輸出一個警告,玩家的最終目的是從第一個房間走到最後一個房間。
    這個遊戲是一個典型的狀態機,當玩家所在房間就是一個狀態。爲實現這個迷宮遊戲,我們可以爲每個房間對應的邏輯便編寫一段代碼,然後用goto語句表示從一個房間移動到另一個房間。
如下例

goto room1 

::room1:: do
	local move = io.read()
	if move == "south" then goto room3
	elseif move == "east" then goto room2
	else
		print("invalid move")
		goto room1
	end
end

::room2:: do
	local move = io.read()
	if move == "south" then goto room4
	elseif move == "west" then goto room1
	else
		print("invalid move")
		goto room2
	end
end

::room3:: do
	local move = io.read()
	if move == "north" then goto room1
	elseif move == "east" then goto room4
	else
		print("invalid move")
		goto room3
	end
end

::room4:: do
	print("Congratulations, you won!")
end

    對於這個簡單的遊戲,讀者可能會發現,使用數據驅動編程是一種更好的設計方法。不過,如果遊戲中的每間房都各自不同,那麼久非常適合使用這種狀態機的實現方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章