Go에서 태그의 용도는 무엇입니까?


392

에서 이동 언어 사양 ,이 태그에 대한 간단한 개요를 언급한다 :

필드 선언 뒤에는 선택적 문자열 리터럴 태그가 올 수 있으며, 이는 해당 필드 선언의 모든 필드에 대한 속성이됩니다. 태그는 리플렉션 인터페이스를 통해 볼 수 있지만 무시됩니다.

// A struct corresponding to the TimeStamp protocol buffer.
// The tag strings define the protocol buffer field numbers.
struct {
  microsec  uint64 "field 1"
  serverIP6 uint64 "field 2"
  process   string "field 3"
}

이것은 매우 간단한 설명 IMO이며, 누군가이 태그가 어떤 용도로 사용될 수 있는지 궁금합니다.


'시맨틱 한'주석 사용에 대한 관련 질문이 있습니다. stackoverflow.com/questions/53101458/…
Bruce Adams

답변:


641

필드에 대한 태그를 사용하면 리플렉션을 사용하여 획득 할 수있는 메타 정보를 필드에 첨부 할 수 있습니다. 일반적으로 구조체 필드가 ​​다른 형식으로 인코딩되거나 디코딩되는 방법 (또는 데이터베이스에서 저장 / 검색)에 대한 변환 정보를 제공하는 데 사용되지만 원하는 메타 정보를 다른 용도로 저장하는 데 사용할 수 있습니다. 패키지 또는 자신의 사용.

의 문서에서 언급했듯이 reflect.StructTag, 규칙에 따라 태그 문자열의 값은 공백으로 구분 된 key:"value"쌍의 목록입니다 . 예를 들면 다음과 같습니다.

type User struct {
    Name string `json:"name" xml:"name"`
}

key일반적으로 후속하는 패키지이다 "value"예를 들면위한 json키 처리 /에 의해 사용되는 encoding/json패키지.

에 여러 정보를 전달해야하는 "value"경우 일반적으로 정보를 쉼표 ( ',') 로 구분하여 지정합니다 . 예 :

Name string `json:"name,omitempty" xml:"name"`

일반적으로 프로세스에서 필드를 제외 '-'하는 "value"수단에 대한 대시 값 ( ) (예 : json해당 필드를 마샬링하거나 마샬링하지 않는 경우 ).

리플렉션을 사용하여 사용자 정의 태그에 액세스하는 예

리플렉션 ( reflectpackage)을 사용하여 구조체 필드의 태그 값에 액세스 할 수 있습니다. 기본적으로 우리는 취득해야 Type우리의 구조체를, 그리고 우리가 함께 예를 들어 필드를 조회 할 수 있습니다 Type.Field(i int)또는 Type.FieldByName(name string). 이 메소드 StructField는 구조체 필드를 설명하고 나타내는 값을 리턴 합니다. 그리고 StructField.Tag타입의 값 StructTag/이 태그 값을 나타내는 설명한다.

이전에는 "컨벤션"에 대해 이야기했습니다 . 당신이 그것을 따르는 경우에, 당신은 사용할 수 있음이 협약 수단 StructTag.Get(key string)태그의 값을 구문 분석하고 반환 방법 "value"key지정을. 규칙은 이에 내장 / 구현 Get()방법. 컨벤션을 따르지 Get()않으면 key:"value"쌍 을 구문 분석 하고 원하는 것을 찾을 수 없습니다 . 그것은 또한 문제가 아니지만, 자신 만의 파싱 로직을 구현해야합니다.

또한 "StructTag.Lookup() Go 1.7에서 추가되었습니다 "Get()" 빈 문자열을 주어진 키와 연관시키는 태그와 주어진 키를 포함하지 않는 태그를 구별하지만" 입니다.

간단한 예를 보자.

type User struct {
    Name  string `mytag:"MyName"`
    Email string `mytag:"MyEmail"`
}

u := User{"Bob", "bob@mycompany.com"}
t := reflect.TypeOf(u)

for _, fieldName := range []string{"Name", "Email"} {
    field, found := t.FieldByName(fieldName)
    if !found {
        continue
    }
    fmt.Printf("\nField: User.%s\n", fieldName)
    fmt.Printf("\tWhole tag value : %q\n", field.Tag)
    fmt.Printf("\tValue of 'mytag': %q\n", field.Tag.Get("mytag"))
}

출력 ( Go Playground 에서 시도 ) :

Field: User.Name
    Whole tag value : "mytag:\"MyName\""
    Value of 'mytag': "MyName"

Field: User.Email
    Whole tag value : "mytag:\"MyEmail\""
    Value of 'mytag': "MyEmail"

GopherCon 2015에는 다음과 같은 구조체 태그에 대한 프레젠테이션이있었습니다.

구조 태그의 여러 얼굴 (슬라이드) (및 비디오 )

일반적으로 사용되는 태그 키 목록은 다음과 같습니다.


28
훌륭한 답변입니다. 이 카르마의 10 배가있는 것보다 여기에 더 유용한 정보가 있습니다.
Darth Egregious

2
아주 좋은 요약!
stevenferrer

2
대단한 답변
Alberto Megía

1
좋은 답변입니다! 감사합니다!
JumpAlways

1
놀라운 답변입니다.이 모든 정보에 감사드립니다!
Sam Holmes

157

다음은 encoding/json인코딩 및 디코딩 중에 필드가 해석되는 방식을 제어하기 위해 패키지 와 함께 사용되는 태그의 간단한 예입니다 .

라이브 체험 : http://play.golang.org/p/BMeR8p1cKf

package main

import (
    "fmt"
    "encoding/json"
)

type Person struct {
    FirstName  string `json:"first_name"`
    LastName   string `json:"last_name"`
    MiddleName string `json:"middle_name,omitempty"`
}

func main() {
    json_string := `
    {
        "first_name": "John",
        "last_name": "Smith"
    }`

    person := new(Person)
    json.Unmarshal([]byte(json_string), person)
    fmt.Println(person)

    new_json, _ := json.Marshal(person)
    fmt.Printf("%s\n", new_json)
}

// *Output*
// &{John Smith }
// {"first_name":"John","last_name":"Smith"}

json 패키지는 필드의 태그를보고 json <=> 구조체 필드를 매핑하는 방법과 json으로 다시 직렬화 할 때 빈 필드를 무시 해야하는지 여부와 같은 추가 옵션을 알려줍니다.

기본적으로 모든 패키지는 필드에서 리플렉션을 사용하여 태그 값을보고 해당 값에 작용할 수 있습니다. reflect 패키지
http://golang.org/pkg/reflect/#StructTag 에 자세한 정보가 있습니다 .

일반적으로 태그 문자열은 선택적으로 공백으로 구분 된 키 : "값"쌍으로 연결됩니다. 각 키는 공백 (U + 0020 ''), 따옴표 (U + 0022 ' "') 및 콜론 (U + 003A ':') 이외의 비 제어 문자로 구성된 비어 있지 않은 문자열입니다. U + 0022 ' "'문자 및 Go 문자열 리터럴 구문을 사용합니다.


6
자바 주석과 같은 종류?
Ismail Badawi

7
@isbadawi : 나는 자바 사람이 아니지만 자바 주석의 정의를 한 눈에봤을 때, 그들은 같은 목표를 달성하고있는 것 같습니다. 런타임에 검사 할 수있는 요소에 메타 데이터 첨부
jdi

15
실제로 자바 주석이 아닙니다. Java 주석은 형식이 안전하며 컴파일 시간을 확인합니다. go와 같은 문자열 리터럴은 아닙니다. Java 어노테이션은 golang 기본 메타 데이터 프로비저닝보다 훨씬 강력하고 강력합니다.
앉아

2
Go 용 MongoDB 드라이버의 일부로 mgo는 bson 패키지의 태그도 사용합니다 (자체로 사용할 수도 있음). BSON 생성 내용을 정확하게 제어 할 수 있습니다. 참조 godoc.org/labix.org/v2/mgo/bson#pkg-files
이노

1
JSON 및 BSON 이외의 다른 예가 있습니까?
Max Heiber

1

태그가 지정된 필드로 패키지를 처리하는 방법을 지정하는 일종의 사양입니다.

예를 들면 다음과 같습니다.

type User struct {
    FirstName string `json:"first_name"`
    LastName string `json:"last_name"`
}

json 태그는 json다음 사용자의 출력을 마샬링 한 패키지에 알립니다

u := User{
        FirstName: "some first name",
        LastName:  "some last name",
    }

이 같은 것입니다 :

{"first_name":"some first name","last_name":"some last name"}

다른 예는 gorm패키지 태그가 데이터베이스 마이그레이션 수행 방법을 선언하는 것입니다.

type User struct {
  gorm.Model
  Name         string
  Age          sql.NullInt64
  Birthday     *time.Time
  Email        string  `gorm:"type:varchar(100);unique_index"`
  Role         string  `gorm:"size:255"` // set field size to 255
  MemberNumber *string `gorm:"unique;not null"` // set member number to unique and not null
  Num          int     `gorm:"AUTO_INCREMENT"` // set num to auto incrementable
  Address      string  `gorm:"index:addr"` // create index with name `addr` for address
  IgnoreMe     int     `gorm:"-"` // ignore this field
}

Emailgorm 태그가 있는 필드의이 예 에서 필드 이메일에 대한 데이터베이스의 해당 열은 varchar 유형과 최대 길이 100이어야하며 고유 인덱스도 있어야한다고 선언합니다.

다른 예는 패키지 binding에서 가장 많이 사용되는 태그입니다 gin.

type Login struct {
    User     string `form:"user" json:"user" xml:"user"  binding:"required"`
    Password string `form:"password" json:"password" xml:"password" binding:"required"`
}


var json Login
if err := c.ShouldBindJSON(&json); err != nil {
     c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
     return
}

이 예제의 바인딩 태그는 API로 전송 된 데이터에 사용자 및 비밀번호 필드가 있어야하며 이러한 필드에 필요에 따라 태그가 지정된다는 진 패키지 힌트를 제공합니다.

따라서 일반적으로 태그는 패키지가 다른 구조체 유형의 데이터로 처리해야하는 방법을 알아야하는 패키지이며 패키지에 필요한 태그에 익숙해지는 가장 좋은 방법은 패키지 문서를 완전히 읽는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.