Go'daki etiketler için kullanımları nelerdir?


392

In Git Dil Şartname , bu etiketlerin kısa bir özetini bahseder:

Alan bildiriminin ardından, karşılık gelen alan bildirimindeki tüm alanlar için bir nitelik haline gelen isteğe bağlı bir dize değişmez etiketi gelebilir. Etiketler bir yansıma arabirimi aracılığıyla görünür hale getirilir, ancak aksi takdirde yok sayılır.

// 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"
}

Bu çok kısa bir açıklama IMO, ve ben kimse bana bu etiketleri kullanmak ne olacağını sağlayabilir merak ediyordum?


'Anlamsal' yorumların kullanımı ile ilgili bir sorum var: stackoverflow.com/questions/53101458/…
Bruce Adams

Bu bağlantının düzeltilmesi stackoverflow.com/q/53487371/1569204
Bruce Adams

Yanıtlar:


641

Bir alanın etiketi, alana yansıma kullanılarak elde edilebilecek meta bilgileri eklemenizi sağlar. Genellikle, bir yapı alanının başka bir formata nasıl kodlandığı veya kodunun nasıl çözüldüğü (veya bir veritabanından saklandığı / alındığı) hakkında dönüşüm bilgisi sağlamak için kullanılır, ancak başka bir amaç için istediğiniz meta bilgileri depolamak için kullanabilirsiniz. paket veya kendi kullanımınız için.

Belgelerinde belirtildiği gibi, reflect.StructTagkural olarak, bir etiket dizesinin değeri, boşlukla ayrılmış bir key:"value"çiftler listesidir, örneğin:

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

keyGenellikle daha sonra bu paketi göstermektedir "value"Örneğin, için jsonanahtarlar işleme / tarafından kullanılan encoding/jsonbir paket.

İçine birden fazla bilgi iletilecekse "value", genellikle virgülle ( ','), ör.

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

Genellikle , alanı işlemden hariç tutma araçları için bir tire değeri ( '-') "value"(örneğin, jsonbu alanı mareşal veya mareşal olmayan anlamında).

Yansıma kullanarak özel etiketlerinize erişme örneği

reflectYapı alanlarının etiket değerlerine erişmek için yansıma ( paket) kullanabiliriz. Temel olarak yapımızdan bir şey edinmeliyiz Typeve daha sonra alanları Type.Field(i int)veya ile sorgulayabiliriz Type.FieldByName(name string). Bu yöntemler StructField, bir yapı alanını tanımlayan / temsil eden bir değer döndürür ; ve bir etiket değerini tanımlayan / temsil eden bir StructField.Tagtür StructTagdeğeridir.

Daha önce "kongre" hakkında konuşmuştuk . Bunu takip ederseniz, kullanabileceğini Bu kongre araçlarının StructTag.Get(key string)bir etiket değerini ayrıştırır ve döndüren yöntemi "value"ait keyBelirttiğiniz. Kongre bu yerleşik / uygulanmaktadır Get()yöntemle. Sözleşmeyi takip etmezseniz, çiftleri Get()ayrıştıramaz key:"value"ve aradığınızı bulamazsınız. Bu da bir sorun değil, ama sonra kendi ayrıştırma mantığını uygulamanız gerekiyor.

Ayrıca StructTag.Lookup()(Go 1.7'de eklenmiştir), " Get()verilen anahtarı içermeyen etiketi boş bir dizeyi verilen anahtarla ilişkilendiren etiketten farklı ancak benzer şekilde ayırır" vardır .

Şimdi basit bir örnek görelim:

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"))
}

Çıktı ( Go Playground'da deneyin ):

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, şu yapı etiketleri hakkında bir sunum yaptı:

Yapı Etiketlerinin Birçok Yüzü (slayt) (ve video )

Sık kullanılan etiket anahtarlarının listesi:


28
Mükemmel cevap. Burada bu karmanın on katından daha yararlı bilgi.
Darth Egregious

2
çok güzel bir özet!
stevenferrer

2
Ne harika bir cevap
Alberto Megía

1
Mükemmel cevap! Teşekkür ederim!
JumpAlways

1
Şaşırtıcı cevap, tüm bu bilgiler için teşekkür ederim!
Sam Holmes

157

encoding/jsonKodlama ve kod çözme sırasında alanların nasıl yorumlandığını kontrol etmek için paketle birlikte kullanılan etiketlere gerçekten basit bir örnek :

Canlı deneyin: 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 paketi, alanın etiketlerine bakabilir ve json <=> struct alanının nasıl eşleneceği ve ayrıca json'a serileştirilirken boş alanları görmezden gelmesi gerekip gerekmediği gibi ek seçenekler söylenebilir.

Temel olarak, herhangi bir paket etiket değerlerine bakmak ve bu değerler üzerinde işlem yapmak için alanlardaki yansımayı kullanabilir. Yansıtma paketinde onlar hakkında biraz daha bilgi var
http://golang.org/pkg/reflect/#StructTag :

Kural olarak, etiket dizeleri isteğe bağlı olarak boşlukla ayrılmış anahtar: "değer" çiftlerinin bir birleşimidir. Her anahtar boşluk (U + 0020 ''), tırnak işareti (U + 0022 '"') ve iki nokta üst üste (U + 003A ':') dışındaki kontrol dışı karakterlerden oluşan boş olmayan bir dizedir. U + 0022 '' 'karakterlerini ve Go dizesi değişmez sözdizimini kullanarak.


6
Java ek açıklamaları gibi?
Ismail Badawi

7
@isbadawi: Ben bir java adamı değilim, ama java ek açıklamalarının tanımına hızlı bir bakışla, evet aynı hedefe ulaşıyor gibi görünüyor; çalışma zamanında incelenebilecek öğelere meta veriler ekleme.
jdi

15
Gerçekten java ek açıklamaları değil. Java ek açıklamaları tür güvenlidir ve derleme zamanı denetlenir - go gibi dize değişmez değerleri değil. Java ek açıklamaları, golang temel meta veri hükümlerinden çok daha güçlü ve sağlamdır.
doymuş

2
Go için MongoDB sürücüsünün bir parçası olarak, mgo, bson paketinde (kendi başına da kullanılabilen) etiketler kullanır. BSON'un ne üretildiği üzerinde hassas kontrol sağlar. Bkz. Godoc.org/labix.org/v2/mgo/bson#pkg-files
Eno

1
JSON ve BSON dışında başka örnekler var mı?
Max Heiber

1

Paketlerin etiketli bir alana nasıl davranacağını belirten bir tür özelliklerdir.

Örneğin:

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

json etiketi jsonaşağıdaki kullanıcının çıktılarını toplayan paketi bilgilendirir

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

şöyle olurdu:

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

diğer bir örnek olarak gormpaket etiketleri, veritabanı geçişlerinin nasıl yapılması gerektiğini bildirir:

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
}

Bu örnekte Email, gorm etiketi olan alan için, alan e-postasına ilişkin veritabanındaki ilgili sütunun varchar ve 100 maksimum uzunluk türünde olması ve ayrıca benzersiz bir dizine sahip olması gerektiğini beyan ederiz.

diğer bir örnek ise bindingdaha çok ginpakette kullanılan etiketlerdir .

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
}

bu örnekteki bağlayıcı etiket, API paketine gönderilen verilerin kullanıcı ve şifre alanlarına sahip olması gerektiği cin paketine ipucu verir, bu alanların gerektiği gibi etiketlenmesine neden olur.

Genel olarak etiketler, paketlerin farklı yapı türlerine sahip verilerle nasıl davranmaları gerektiğini bilmesi gereken verilerdir ve bir paketin ihtiyaç duyduğu etiketlere aşina olmanın en iyi yolu, bir PAKET BELGESİNİ TAMAMEN OKUMAKTIR.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.