티스토리 뷰

gRPC

[gRPC] Map, Package

Jaime.Lee 2021. 8. 9. 01:59

Map

메시지를 정의할 때 맵을 사용하기 위해 프로토콜 버퍼는 간편한 방법을 제공합니다.

map<key_type, value_type> map_field = N;

key_type은 정수나 문자열 타입이 될 수 있습니다. 이는 스칼라 타입 중 부동 소수점이나 바이트를 제외한 모든 타입에 해당합니다.

다만, 열거형은 사용할 수 없습니다.

value_type은 다른 map을 제외한 모든 타입이 될 수 있습니다.

map<string, Project> projects = 3;

이렇게 문자열에 Project라는 메시지 타입을 매핑하여 사용할 수 있습니다. map은 어떤 언어에서든 사용법이나 선언하는 방법이 비슷하므로 추가적인 설명은 필요하지 않을 거 같습니다.

  • maprepeated 타입이 될 수 없습니다.
  • mapitem들은 순서를 가지지 않습니다.
  • .proto 타입에 대한 텍스트 포맷을 생성할 때 map은 키로 정렬됩니다. 숫자 키의 경우 숫자 오름차순으로 정렬됩니다.
  • 파싱하거나 병합할 때 중복된 키가 존재한다면 마지막 키가 사용됩니다.
  • 텍스트 포맷에서 map을 파싱할 때는 중복 키가 있는 경우 파싱이 실패할 수 있습니다.
  • 키는 존재하고 값을 제공하지 않는 경우 언어마다 다르게 직렬화됩니다. C++, Java, Kotlin, Python에서는 기본 값이 직렬화되지만 다른 언어에서는 아무 것도 직렬화되지 않습니다.

생성된 map API는 현재 모든 proto3를 지원하는 언어에서 사용 가능하고 관련해서는 여기를 참조하시면 됩니다.

하위 호환성

map 문법은 아래 예시와 실제로 동일하게 동작하므로 맵을 지원하지 않는 프로토콜 버퍼를 사용하더라도 아래처럼 구현하게 되면 여전히 map 구조로 데이터를 처리할 수 있습니다.

message MapFieldEntry {
  key_type key = 1;
  value_type value = 2;
}

repeated MapFieldEntry map_field = N;

map을 지원하는 모든 프로토콜 버퍼 구현은 위의 정의에서 허용할 수 있는 데이터를 생성하고 허용해야 합니다.

Package

프로토콜 메시지 타입 간의 이름 충돌을 방지하기 위해 패키지 지정자를 .proto 파일에 추가할 수 있습니다.

package foo.bar;
message Open { ... }

그런 다음 메시지 타입의 필드를 정의할 때 패키지 지정자를 사용할 수 있습니다.

message Foo {
  ...
  foo.bar.Open open = 1;
  ...
}

패키지 지정자가 생성된 코드에 영향을 미치는 방식은 선택한 언어에 따라 다릅니다.

  • C++에서 생성된 클래스는 C++ 네임스페이스 내부에 래핑(wrapping)됩니다. 예를 들어 Open은 네임스페이스 foo::bar에 있습니다.
  • JavaKotlin에서는 .proto 파일에 java_package 옵션을 명시적으로 제공하지 않는 한 패키지가 Java 패키지로 사용됩니다.
  • Python에서 패키지 지시문은 무시됩니다. Python 모듈은 파일 시스템의 위치에 따라 구성되기 때문입니다.
  • Go에서 패키지는 .proto 파일에 go_package 옵션을 명시적으로 제공하지 않는 한 Go 패키지 이름으로 사용됩니다.
  • Ruby에서 생성된 클래스는 중첩된 Ruby 네임스페이스 안에 래핑되어 필요한 Ruby 대문자 스타일로 변환됩니다(첫 글자는 대문자로, 첫 글자가 글자가 아닌 경우 PB_가 앞에 추가됨). 예를 들어, OpenFoo::Bar 네임스페이스에 있습니다.
  • C#에서는 .proto 파일에 csharp_namespace 옵션을 명시적으로 제공하지 않는 한 PascalCase로 변환한 후 패키지가 네임스페이스로 사용됩니다. 예를 들어 OpenFoo.Bar 네임스페이스에 있습니다.

패키지 및 이름 확인

프로토콜 버퍼 언어의 타입 이름 확인은 C++처럼 작동합니다.

먼저 가장 안쪽 범위가 검색되고 다음 안쪽 범위가 검색되는 방식으로 각 패키지가 상위 패키지의 "내부"로 간주됩니다.

선행 '.' (예: .foo.bar.Baz)은 가장 바깥쪽 범위에서 시작하는 것을 의미합니다.

프로토콜 버퍼 컴파일러는 가져온 .proto 파일을 구문 분석하여 모든 타입 이름을 확인합니다.

각 언어의 코드 제너레이터는 범위 지정 규칙이 다른 경우에도 해당 언어의 각 타입을 참조하는 방법을 알고 있습니다.


본 포스팅은 gRPC 공식 문서를 참고하여 작성하였습니다.

댓글