2014-07-17 7 views
3

키없이 참조 될 때 테이블이 자신에 대한 참조가 아닌 특정 값을 반환 할 수 있습니까?루아 테이블의 반환 값을 재정의 할 수 있습니까?

의 나는 다음과 같은 테이블이 있다고 가정 해 봅시다 :

local person = { 
    name = "Kapulani", 
    level = 100, 
    age = 30, 
} 

루아, 나는 아주 쉽게 "person.name", "person.level"또는 "인 person.age"를 참조하여 값을 얻을 수 있습니다 예상대로 그러나 필자는 "person"을 참조하고 "table :"대신 "person.name"값을 반환하고 싶을 수도 있습니다.

즉, person.x (또는 person [x])가 테이블에서 적절한 항목을 반환하지만 키가없는 사람이 person.name (또는 person [ "name "]). 내가 찾을 수 없었던이 메커니즘이 있습니까?

__index는 키가 존재하지 않는 경우에만 적용되므로 메타 테이블에서는 성공하지 못했습니다. 내가 별도의 테이블에 "사람"을 넣으면, 내가 가지고 올 수 :

이) (__index에서, 나에게 할 뚜렷한 방법이 없다 제외하고 나, 특별한 처리를 할 __index 사용할 수 있습니다
local true_person = { 
    ... -- as above 
} 

local env_mt = { 
    __index = function(t, k) 
     if k == 'person' then 
      return true_person 
     end 
    end 
} 

local env = setmetatable({}, env_mt) 

, env.person에 대한 요청 (true_person.name을 반환 할 곳) 또는 env.person [key] (true_person을 테이블로 반환하려는 경우 'key'를 적절히 액세스).

의견이 있으십니까? 나는 다르게 접근 할 수 있지만, 나는이 선을 따라 접근 할 수 있기를 희망한다.

+2

당신은 자신의 DSL을 만들기 위해 루아의 구문과 싸우고 있습니다. 정말로 이점이 있습니까? 예가 도움이 될 것입니다. 어쨌든 __call 메타 메소드를 사용해 보거나 간단하게 : default() 메소드를 일반 또는 테이블 특정 구현과 함께 모든 테이블에 추가 할 수 있습니다. –

+0

나는 장단점을 분명히 고려하고있다. 나는 ** __ call **을 가지고 놀았으며, **() **에 대한 필요성을 피하기를 희망했지만, 내가 찾고있는 것에 조금 더 가깝습니다.내가 바라는 장점은 기존 구문과 루아 구문 사이의 '번역'양을 제한함으로써 루아가 오류를 던지면 출력이 상대적으로 의미 있고 사용자에게 인식 될 수 있다는 것입니다. 따라서 ** 및 **을 ** 및 ** 및 **으로 ** 또는 **을 ** 또는 **로 변환하는 것은 이상하지는 않지만 ** 사람 **에서 ** 사람()으로 변환 ** ** person.name **에 번역이 필요하지 않은 장소는 조금 이상 할 수 있습니다. – Kapulani

답변

2

테이블이 __tostring 메타 테이블 항목을 설정하여 문자열로 사용할 때 당신은 그것을 할 수 있습니다 :

$ cat st.lua 
local person = { 
    name = "Kapulani", 
    level = 100, 
    age = 30, 
} 

print(person) 
print(person.name) 
print(person.age) 

setmetatable(person, {__tostring = function(t) return t.name end}) 
print(person) 

$ lua st.lua 
lua st.lua 
table: 0x1e8478e0 
Kapulani 
30 
Kapulani 
+0

이것은 매우 유용하고 간단합니다. 디폴트 값이 문자열이 아니라 숫자라면? __tonumber는 유효한 메타 메소드가 아닌 것 같습니다. 숫자 값을 사용하는 해결 방법이 있습니까? 나 대신 이름 대신 나이를 써? – Kapulani

+2

@ Kapulani 그렇게 할 수는 있지만 __tostring이 문자열을 반환해야한다는 강력한 계약이라고 말하고 싶습니다. –

+1

메타 메서드 이름은 수행되는 작업 (및 기능)입니다. 당신은 분명히 그 메타 메서드로부터 숫자를 반환 할 수 있습니다. @TomBlodget이 말하듯이, 조금 이상하지만 대부분의 경우에는 아무 것도 해치지 않을 것입니다. (일반적인 문자열 사용 사례는 숫자를 즉시 ​​문자열로 자동 변환합니다.) 누군가가 string metamethod/etc를 사용하려고 시도하는 경우에만 해를 입을 수 있습니다. 반환 값에 직접. –

1

나는 그것이에 날아 때문에 당신을 위해 무엇을 요구하는 것은 좋은 생각입니다 확실하지 않다을 구성 성의 얼굴. 보통 사람은 다음과 같은 두 가지 프로그램이 같은 일을 기대하지만 당신은 그들을 또한 할당이 어떻게 작동하는지 명확하지 다르게

print(person.name) 

local p = person 
print(p.name) 

그 행동하고자합니다. person.age = 10은 연령을 변경해야하지만 person = otherPerson은 연령이 아니라 perrson에 대한 참조를 변경해야합니다. 당신의 구성 성 신경 쓰지 않고 설 포닐 데이터를 읽는 경우

는 문제를 해결하기 위해 다음 더 직접적인 방법은

query("person.age") -- 17 
query("person.name") -- "hugomg" 
query("person")  -- 17; query gets to default to whatever it wants. 

유지하기 위해 문자열 인코딩 필드를받는 쿼리 기능을하는 것입니다 구문은 더, 당신이 선택 괄호

q"person.age" 
q"person" 

를 생략 할 수 있습니다 또는 전역 테이블에 __index 메타 메소드를 확장 할 수있는 경량 _G

setmetattable(_G, { __index = function(self, key) return query(key) end }) 

print (person_age) -- You will need to use "_" instead of "." for the 
         -- query to be a valid identifier.