2013-08-29 11 views
7

Niektóre funkcje Lua zwracają nil, aby zasygnalizować użytkownikowi, że funkcja nie może wykonać jakiegoś zadania (np. tonumber(), string.find()).Powracanie 'nil' z funkcji Lua w C i zwracanie 0 wartości

W C returnig nil odbywa się to tak:

int some_function(lua_State* L) { 
    ... 
    if (some condition) { 
     lua_pushnil(L); 
     return 1; 
    } 
    ... 
} 

Ja jednak zastanawiam się, czy to jest w porządku, aby wykonać następujące czynności zamiast:

int some_function(lua_State* L) { 
    ... 
    if (some condition) { 
     return 0; 
    } 
    ... 
} 

Jest krótszy. Spróbowałem i wydaje mi się, że działa, ale nie wiem, czy to projekt. Sprawdziłem kod źródłowy Lua i nie widzę tego wzoru, więc zastanawiam się, czy jest to uzasadnione.

Czy dwa różne sposoby zwrotu są równoważne z nil?

(BTW, wiem wszystko o sygnalizacji błędów za pomocą wyjątków (czyli lua_error()), więc proszę, nie wspominając go).

UPDATE:

widzę teraz, że istnieje subtelna różnica między dwiema metodami: print((function() end)()) nic by nie wydrukowało, podczas gdy print((function() return nil end)()) wyświetliłoby "zero". Nie wiem, jak ważne jest to.

+0

"Przeanalizowałem kod źródłowy Lua i nie widzę tego powrotu 0 wzór" Jak ciężko wyglądałeś? Wszystkie funkcje biblioteczne Lua, które nie zwracają wartości (np. Print, table.insert, itp.) Zwracają 0 w swoich implementacjach C. – Mud

+0

@Mud: Przykłady, które podajesz, 'print()' i 'table.insert()', nie mają znaczenia, ponieważ te funkcje nie powinny zwracać niczego. Mówię o funkcjach, które normalnie * zwracają * wartości zwracane, np. 'Tonumber()', a jeśli sprawdzasz ich źródło, zobaczysz, że robią 'lua_pushnil (L); return 1; '. –

Odpowiedz

12

Funkcje w Lua mogą zwrócić nil, ale mogą również nie zwracać niczego, a to zachowanie nie jest dokładnie równoważne, chociaż w większości przypadków wyniki będą takie same.

Poniższy skrypt Lua pokazuje jak wykrywać jak ceni wielu zwrócić powraca funkcyjne:

local function PrintNRetVals(...) 
    local nargs = select('#', ...) 
    print("Number of values returned: " .. nargs) 
end 

local function ReturningSomething() 
    return "hello" 
end 

local function ReturningNil() 
    return nil 
end 

local function ReturningNothing() 
    return 
end 


PrintNRetVals(ReturningSomething()) --> 1 
PrintNRetVals(ReturningNil())   --> 1 
PrintNRetVals(ReturningNothing())  --> 0 

powiedziałem zachowanie jest prawie równoważne, ponieważ jak najszybciej starają się przypisać do zmiennej wynikiem funkcja ta zmienna otrzyma nil w obu przypadkach, więc kolejny kod nie będzie w stanie określić różnicy. Ale, jak pokazałem powyżej, możesz wykryć różnicę, jeśli naprawdę potrzebujesz.

+0

jest jednak ogromna różnica, jednak jeśli użyjesz 'tostring (ReturnNothing())' lub 'type (ReturnNothing())' spowoduje to błąd, ale jeśli zostanie użyty w kontekście boolowskim, lua uzna to za fałszywe. –

+0

@XavierCombelle Jak wskazałem w mojej odpowiedzi, * możesz * odróżnić, jeśli naprawdę potrzebujesz. A te dwie wbudowane funkcje Lua robią dokładnie to: rozróżniają te dwa przypadki (najprawdopodobniej dlatego, że w tym kontekście brak wartości, w przeciwieństwie do wartości 'nil', jest prawdopodobnie błędem programowania, a nie zamierzonym). –

+0

Miałem kod wzdłuż tych linii 'jeśli nie ReturnNothing(), a następnie wydrukować (tostring (ReturnNothing())) koniec' zajęło dość długi czas debugowania (z mojego tła Pythona) powodem poniższego wyjątku 'zły argument # 1 do 'tostring' (oczekiwana wartość). "Chcę powiedzieć, że jest to błąd programistyczny w obu przypadkach lub w żadnym. –

5

Tak, jest to całkowicie poprawne. Jeśli próbujesz zażądać/przypisać więcej wartości zwracanych niż jest (bez względu na to, czy spróbujesz uzyskać jedną czy dziesięć), otrzymasz nil dla niezdefiniowanych (tj. Tych, które nie zostały zwrócone).

function test1() 
    return 5 
end 

local a, b = test1() 
-- a = 5, b = nil 

function test2() 
    return 1, 2 
end 

local c, d, e = test2() 
-- c = 1, d = 2, e = nil 

function test3() 
end 

local f, g = test3() 
-- f = nil, g = nil 

Prawdopodobnie nie można go znaleźć w źródle Lua, ponieważ nie jest to żaden specjalny przypadek ani nic. To tylko ogólny sposób Lua do obsługi wartości zwracanych.

Aktualizacja:

Różnica zauważyłeś podczas próby wydrukowania wartości zwracanych jest fakt, że nie jest to tylko zadanie. Oczywiście istnieje niewielka różnica między zwrotem nil i nie zwracaniem nic - i można tam rozróżnić. Na koniec musisz po prostu upewnić się, że prawidłowo dokumentujesz zachowanie swojej funkcji, tj. Mówisz użytkownikowi, co ma się wydarzyć. Na przykład zwrot nil (lub uzyskanie nil w przypisaniu) może reprezentować stan błędu, ale można również zwrócić wszystko, gdy wystąpił błąd i zwrócić nil, jeśli pewna wartość ma być nieprawidłowa lub nil (ale nie wystąpił błąd).

+0

Dzięki. Edytowałem swoją odpowiedź, aby powiedzieć o subtelnej różnicy między zwracaniem 'nil' a nie zwracaniem czegokolwiek. Ale jestem nowicjuszem w Lua, więc sam nie mogę ocenić, czy to ważne, czy nie. Znam przyczynę tego zachowania (czytam książkę PiL). Zastanawiam się tylko, dlaczego, na przykład, w źródle "tonumber()" (w lbaselib.c) oni zwracają "zero". –

+0

Dla Twojej dodanej aktualizacji: Zasadniczo zależy to od interpretacji. Oczywiście istnieje różnica między zwracaniem nie jednej wartości a zwracaniem jednej wartości wynoszącej 'nil'. W zadaniu nie będzie żadnej różnicy, ale rzeczywiście zauważysz różnicę w zależności od tego, jak używasz zwróconych wartości. – Mario

2

(To nie jest odpowiedź, tylko opinia na ten temat)

Jak dla mnie, to sztuczne różnica między nil i no value jest niespójny i dość irytujące.

local function f1() return nil end 
local function f0() end 

local v1 = f1()  -- OK, assigns nil 
print(type(f1())) -- OK, prints 'nil' 

local v0 = f0()  -- OK, assigns nil 
print(type(f0())) -- Why the hack it raises an error? 

IMHO, parametr mijania funkcyjnego musi być w pełni zgodne z semantyczny od instrukcji przypisania.

+0

Jeśli jesteś w niebezpieczeństwie dostania się do takiej sytuacji, możesz napisać tak: 'print (type ((f0())))'. A błąd pochodzi od funkcji C "typ", a nie od języka. Tak, 'type' jest w stdlib, ale wciąż sam język jest zgodny co najmniej. – dualed

+0

to samo zachowanie appen, jeśli używasz 'tostring' –

Powiązane problemy