본문으로 건너뛰기

선언된 struct의 신원 — 한 번 선언되는 타입

문서 목록으로

상태: 모든 언어에 구현되었습니다. 8절의 「확인할 것」은 모두 확인되었습니다.

두 테이블이 같은 struct 로 타이핑한 그룹이 같은 타입이 되는 것입니다. 로드맵의 다음 항목이고, 형식은 움직이지 않는 대신 모든 언어의 생성 코드가 움직입니다.


1. 지금 나오는 것

레코드 타입은 테이블마다 만들어지고 그 테이블의 산출물 안에 선언됩니다.

언어이름어디에
C#<그룹>Entry테이블의 레코드 클래스 안에 중첩. 접두가 아예 없습니다
TypeScript<그룹>Entry그 테이블의 모듈
Go · Rust · Dart<테이블><그룹>Entry테이블 이름이 앞에 붙습니다
C · C++<테이블레코드>_<그룹>_entry같은 자리, 다른 표기

두 테이블이 각각 reward 그룹을 Reward 로 타이핑하면, C#은 같은 이름의 다른 타입 둘을 내고 나머지는 다른 이름의 다른 타입 둘을 냅니다. 어느 쪽이든 하나를 받는 함수를 쓸 수 없습니다.

이름이 선언이 아니라 그룹에서 옵니다. 실측하면 Bonus 로 타이핑된 bonus 그룹이 BonusEntry 로 나옵니다 — 시트의 그룹 이름에 Entry 를 붙인 것입니다. 그래서 두 시트가 같은 선언을 rewardprize 로 각각 적었다면 오늘은 RewardEntryPrizeEntry 가 되고, 이 작업 뒤에는 둘 다 Reward 가 됩니다. 쓰는 쪽에서 보이는 이름이 바뀌는 것이고, 그것이 이 작업의 diff가 큰 이유입니다.

2. 접두어 제거로 부족한 이유

<테이블><그룹>Entry 에서 테이블 이름을 떼면 이름은 같아집니다. 선언은 여전히 두 번 됩니다. 필요한 것은 이름의 문제가 아니라 신원의 문제입니다.

선언이 타입의 신원입니다. 그룹이 Reward 로 타이핑되었다는 것은 그 그룹의 원소가 Reward 라는 뜻이지, Reward 를 닮았다는 뜻이 아닙니다.

3. 공유되는 그룹과 그대로인 그룹

그룹나오는 것
선언으로 타이핑된 그룹그 선언의 이름을 가진 타입 하나. 두 테이블이 그것을 가리킵니다
이름 없는 인라인 그룹지금 그대로입니다 — pos.x · pos.y 는 시트가 그 자리에서 적은 모양이고, 공유할 신원이 없습니다

판정은 하나입니다 — 시트가 아니라 선언이 신원입니다. 두 시트가 우연히 같은 멤버를 같은 순서로 기재하였다는 것은 같은 타입이라는 근거가 되지 않습니다.

4. 공유의 전제 — 부분 집합의 부재

바인딩은 선언의 살아 있는 멤버 전부에 컬럼을 요구합니다 (RefuseMembersWithNoColumn). 그래서 바인딩된 그룹은 언제나 선언의 전체 모양입니다.

부분 집합이 허용되었다면 이 작업이 성립하지 않았을 것입니다 — 멤버 셋만 적은 테이블과 다섯을 적은 테이블이 같은 타입일 수 없고, 그러면 「선언 하나가 타입 하나」가 아니라 「사용된 멤버 조합마다 타입 하나」가 됩니다. 이미 있는 거절이 이 설계의 전제입니다.

5. 제약이 갈릴 때의 타입

한 테이블이 count 컬럼에 (min=1) 을 적고 다른 테이블이 적지 않았을 때, 타입은 여전히 하나입니다.

제약은 검증이지 표현이 아닙니다. 레코드 멤버별 옵셔널이 같은 판정을 이미 내려 두었습니다 — 무엇이 참이어야 하는지를 규정하는 것과 무엇이 표현 가능해야 하는지를 규정하는 것은 다른 등급입니다. 컬럼의 괄호 메타는 선언의 것과 교집합으로 좁혀지고, 좁혀진 결과는 그 컬럼의 셀을 검사하는 데 쓰일 뿐 생성되는 타입에 나타나지 않습니다.

옵셔널은 다릅니다T? 는 표현입니다. 선언이 icon string? 이면 타입의 멤버가 옵셔널이고, 그것은 두 테이블에 같습니다. 컬럼이 그것을 뒤집을 수 없다는 것도 이미 그 문서의 판정입니다.

6. 따라갈 선례 — 다형 타입

같은 문제를 이미 같은 방법으로 풀었습니다. Model.PolymorphicTypes의 주석이 그 근거를 적어 두었습니다.

모델 수준이지 테이블 수준이 아닌 것은, 선언이 타입 하나이기 때문입니다. 변종을 그것을 쓰는 테이블마다 내는 생성기는 이름이 같고 같은 타입이 아닌 타입들을 만들고, 그러면 그것 하나를 받는 것을 아무것도 쓸 수 없습니다 — 한 파일에 선언한 이유의 반대입니다.

그래서 이 작업은 새 방법이 아니라 그 자리를 넓히는 것입니다. 다형 타입이 이미 structs/ 로 나가고 있고, 선언된 레코드 타입도 거기로 갑니다.

7. 모델에 필요한 것

지금 바인딩은 컬럼에 타입을 주고 어느 선언이었는지를 남기지 않습니다 (BindGroup). 그룹이 Reward 로 타이핑되었다는 사실은 바인딩이 끝나는 순간 사라집니다.

더할 것무엇
그룹이 든 선언의 이름SerialField 가 「이 그룹은 어느 선언인가」를 답할 수 있어야 합니다
모델 수준의 목록실제로 쓰인 선언들. 다형 타입의 목록과 같은 자리

쓰이지 않은 선언은 목록에 없습니다. .tbs 에 적혀 있고 어느 시트도 쓰지 않은 struct까지 타입으로 내면, 선언 파일이 산출물의 크기를 정하게 됩니다.

8. 언어별 자리

다형 타입이 이미 가 있는 자리를 그대로 씁니다. 확인이 필요한 것을 함께 적습니다.

언어어디에확인할 것
C#structs/지금은 테이블 클래스 안에 중첩되어 있습니다. 밖으로 나오면 이름이 짧아지므로 기존 타입과 겹칠 수 있습니다
TypeScriptstructs/테이블 모듈이 그것을 import 합니다
Go · Rust · Dart패키지·크레이트 수준테이블 이름 접두가 사라지므로 같은 이름의 다른 것과 겹칠 수 있습니다
C · C++공용 헤더C에는 네임스페이스가 없어 접두가 이름의 전부입니다. 파일 접두는 남습니다
Java · Kotlin · Swift패키지·모듈 수준의 타입 하나
Lua · Python · PHP · Ruby타입 선언이 없거나 문서용이므로 움직이는 것이 적습니다
UnrealUSTRUCT테이블 안에 있던 것이 모듈 수준으로 나오면 리플렉션 등록 자리가 바뀝니다. UHT 게이트가 그것을 봅니다

9. 움직이는 것과 움직이지 않는 것

무엇어떻게
형식무변경. 레코드 타입의 이름은 파일에 실리지 않습니다 — 와이어는 잎마다 컬럼 하나입니다
모든 언어의 생성 코드 골든움직입니다. 이 작업의 diff가 곧 리뷰 대상입니다
아래 레벨도 함께공유 타입 안의 레벨은 그 타입의 일부입니다. 테이블이 그것을 따로 선언하면 같은 모양의 타입이 둘 생기고 서로 대입되지 않습니다 - containers 가 그것을 잡았습니다
.tcb한 바이트도 움직이지 않아야 합니다

마지막 줄이 이 작업의 게이트입니다. declareddeclared-expanded가 같은 테이블을 두 방법으로 적고 .tcb 가 바이트 동일한 것을 이미 확인하고 있으므로, 그 쌍이 계속 통과하는 것이 「형식은 안 움직였다」의 증거입니다.

10. 남은 결정

무엇선택지
선언 이름이 테이블·enum과 겹칠 때닫혔습니다. 테이블·상수셋은 RefuseNamesTheSheetsAlreadyGave 가 이미 보고 있었고, 빠져 있던 enum을 채웠습니다 — 결함과 고침
중첩 선언struct의 멤버가 struct일 때 안쪽도 공유 타입이 되는지. 된다고 보는 것이 자연스럽습니다 — 안쪽도 선언이므로
한 테이블만 쓰는 선언그래도 별도 자리로 낼 것인지. 낸다고 보는 것이 자연스럽습니다 — 쓰는 곳의 수가 타입의 신원을 바꾸지 않습니다
set · map 인 그룹문제가 아니었습니다 — 10.1
C#의 중첩 해제하기로 하였습니다 — 10.2

10.1 컨테이너를 든 그룹

컨테이너 표면이 레코드 타입 안에 생성되므로(csharp-table.sbnrt.is_map), 같은 선언을 한 테이블은 map 으로 다른 테이블은 배열로 쓰면 두 타입이 달라질 것으로 보았습니다. 그렇게 될 수 없습니다.

컨테이너는 선언의 멤버에 붙습니다 — field prices map<int,int>. 그 선언을 쓰는 모든 테이블이 같은 컨테이너를 받습니다
시트가 그룹에 컨테이너를 붙이려면 타입 칸이 Bagset<…> 을 동시에 말해야 하는데, 타입 칸은 타입 표현 하나입니다
컨테이너인 레벨은 선언된 타입이 아닙니다map<int,Reward> 는 struct 이름이 아니므로 그 레벨의 신원은 비어 있고, 공유되는 것은 그 아래의 Reward 입니다

그래서 컨테이너를 든 그룹도 그대로 공유됩니다.

10.2 C#의 중첩과 들여쓰기

C#은 레코드 타입을 테이블의 레코드 클래스 안에 중첩합니다. 밖으로 나오면 둘이 걸립니다.

무엇내용
이름이 바뀝니다LoadoutRecord.RewardEntry 를 쓰던 코드가 Reward 를 씁니다. 선언으로 타이핑한 그룹에만 해당하므로 범위는 좁습니다
템플릿이 갈립니다중첩된 것은 8칸, 네임스페이스 수준은 4칸으로 들여씁니다. 같은 블록을 두 자리에서 쓰려면 들여쓰기를 맞출 방법이 필요하고, 지금 템플릿 엔진에는 그 자리가 없습니다

두 번째가 실제 비용입니다. 이름 없는 그룹은 테이블마다 남아야 하므로(3절) 두 자리가 다 필요하고, 블록을 복사하지 않으려면 공유 타입을 무언가 안에 넣어 깊이를 맞추거나 (Records.Reward 처럼 이름이 길어집니다) 들여쓰기가 어긋난 파일을 내야 합니다.


부록: enum 이름 충돌

이 문서를 쓰면서 「검사가 없다」고 기재하였다가, 확인해 보니 테이블과 상수셋은 이미 보고 있었고 enum만 빠져 있었습니다. 빠진 자리는 결함이었으므로 이 설계와 별개로 고쳤습니다.

무엇
.tbs 의 struct 이름 = 시트의 테이블 이름두 선언을 가리켜 보고같습니다
.tbs 의 enum 이름 = 시트의 enum 이름첫 데이터 셀을 가리켜 「그 enum에 없는 라벨」로 보고두 선언을 가리켜 보고

보고가 원인이 아니라 결과를 가리키고 있었습니다. 선언 파일의 enum은 시트를 읽기 전에 모델에 들어가고, 주 레이아웃의 중복 검사는 자기 시트의 선언들끼리만 비교합니다. 그래서 짝이 아무 데서도 걸리지 않았고, 두 enum의 라벨이 다르므로 그 라벨을 쓴 첫 셀이 대신 보고되었습니다 — 두 선언에서 여러 걸음 떨어진 자리입니다.

고친 곳무엇
주 레이아웃시트의 enum을 모델에 넣기 전에 이미 있는 이름인지 봅니다. 시트의 셀을 가리키고 상대의 자리를 함께 댑니다
SchemaDeclarations그 아래의 받침. 선언 파일이 넣은 것은 건너뜁니다 — 같은 목록에 있으므로, 가리지 않으면 자기 자신과 충돌한다고 보고합니다

시트당 테이블 레이아웃은 이미 막고 있었습니다(EnumRedefined). 한 레이아웃만 비어 있었다는 것이 이것이 설계의 구멍이 아니라 그 레이아웃의 누락이라는 근거입니다.