Go yapılarında varsayılan değerler nasıl ayarlanır?


143

Aşağıdaki soruya birden fazla cevap / teknik vardır:

  1. Golang yapılarına varsayılan değerler nasıl ayarlanır?
  2. Golang'daki yapıları başlatma

Birkaç cevabım var ama daha fazla tartışma gerekiyor.



@icza Cevabınız bunu yapmanın bir yolunu veriyor ama Soru Başlığı'na girdiğinizde, çok özel bir soru olduğu için hiçbir şekilde benzer veya aranabilir değil. Bağlantıyı yanıtıma ekleyeceğim.
Prateek

Burada iki soru var, birini seçin. İlk soruyu seçtiğinizi varsayarsak (soru başlığına göre), lütfen önceki araştırmanız ve diğer yanıtlarınızın nerede daha fazla tartışma gerektirdiğiyle ilgili daha spesifik olun.
Duncan Jones

Yanıtlar:


96

Olası bir fikir, ayrı yapıcı işlevi yazmaktır

//Something is the structure we work with
type Something struct {
     Text string 
     DefaultText string 
} 
// NewSomething create new instance of Something
func NewSomething(text string) Something {
   something := Something{}
   something.Text = text
   something.DefaultText = "default text"
   return something
}

6
Evet, bu benim cevabımda da bahsettiğim yollardan biri ama kimseyi sadece bu fonksiyonu kullanmaya zorlamanın hiçbir yolu yok.
Prateek

@Prateek bu ya da çirkin ve aşırı karmaşık bir arayüz kullanın.
OneOfOne

31
@Prateek evet, yalnızca türünü dışarıda bırakmanız durumunda insanları bu kurucuyu kullanmaya zorlayabilirsiniz. Sen fonksiyonunu aktarabilir NewSomethingve hatta alanları Textve DefaultText, ama sadece yapı türü ihracat yapmamaktadır something.
Amit Kumar Gupta

1
Sorun daha da kötüsü ... bir üçüncü taraf (örneğin kütüphane) yapınızı örneklemek için kullanılıyorsa ( reflect.New()örneğin, aracılığıyla ), özel olarak adlandırılmış fabrika işlevinizi bilmeniz beklenemezdi. Bu durumda ve dilin değiştirilmesinin kısa olmasının, sadece (kütüphanenin kontrol edebileceği bir arayüz) yapabileceğini düşünüyorum.
edam

1
Varsayılanı ayarlamak iyidir, ancak bazen varsayılanı geçersiz kılmak isteyebilirsiniz. Bu durumda, varsayılan olmayan bir değere sahip bir yapı başlatamayacağım. benim için biraz sinir bozucu
Juliatzin

68
  1. Yapıyı almak için bir yöntemi zorlayın (yapıcı yolu).

    Gönderen bu yazı :

    İyi bir tasarım, türünüzü dışa aktarmamaktır, ancak yapınızı NewMyType()/ türünüzü düzgün bir şekilde başlatabileceğiniz gibi dışa aktarılmış bir yapıcı işlevi sağlamaktır . Ayrıca somut bir türü değil, bir arayüz türü döndürün ve arayüz, başkalarının değerinizle yapmak istediği her şeyi içermelidir. Ve somut tipiniz elbette bu arayüzü uygulamalıdır.

    Bu, tipin kendisini dışa aktarılarak yapılabilir. NewSomething işlevini ve hatta Text ve DefaultText alanlarını dışa aktarabilirsiniz, ancak yapı türü bir şeyi dışa aktarmayın.

  2. Kendi modülünüz için özelleştirmenin başka bir yolu, varsayılan değerleri ayarlamak için bir Config yapısı kullanmaktır (bağlantıdaki Seçenek 5). Ama iyi bir yol değil.




FWIW, bence 'Seçenek 3' - en azından geri dönüş makinesi bağlantısında. (Orada 'Seçenek 5' yoktur).
decimus phostle

32

Victor Zamanian'ın yanıtında 1. seçenekle ilgili bir sorun, tür dışa aktarılmazsa, paketinizin kullanıcılarının bunu işlev parametreleri vb. Türü olarak bildirememesidir. Bunun bir yolu, yapı örneğin

package candidate
// Exporting interface instead of struct
type Candidate interface {}
// Struct is not exported
type candidate struct {
    Name string
    Votes uint32 // Defaults to 0
}
// We are forced to call the constructor to get an instance of candidate
func New(name string) Candidate {
    return candidate{name, 0}  // enforce the default value here
}

Bu, dışa aktarılan Aday arayüzünü kullanarak işlev parametre türlerini bildirmemizi sağlar. Bu çözümden görebileceğim tek dezavantaj, tüm yöntemlerimizin arayüz tanımında bildirilmesi gerektiğidir, ancak bunun yine de iyi bir uygulama olduğunu iddia edebilirsiniz.


Güzel basit bir örnek.

13

Bunu, birden çok varsayılana izin veren etiketlerle yapmanın bir yolu vardır.

2 Varsayılan etiketleri ile, aşağıdaki yapı var varsayalım default0 ve default1 .

type A struct {
   I int    `default0:"3" default1:"42"`
   S string `default0:"Some String..." default1:"Some Other String..."`
}

Artık varsayılanları ayarlamak mümkün.

func main() {

ptr := &A{}

Set(ptr, "default0")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=3 ptr.S=Some String...

Set(ptr, "default1")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=42 ptr.S=Some Other String...
}

İşte bir oyun alanındaki tam program .

Daha karmaşık bir örnekle ilgileniyorsanız, dilimler ve haritalarla söyleyin, o zaman creasty / defaultultse'a bir göz atın


Çok teşekkürler! Kütüphanenin önerdiği kodun aynısını yazmaya başladım ve bu yazıyla karşılaştım. Tam olarak beklediğiniz şeyi yapar ( github.com/creasty/defaults ). Değeriniz yoksa varsayılanı ayarlar, ancak değişkeninize bir değer atadıysanız, varsayılanı atamaz. Yaml.v2 kütüphanesi ile oldukça iyi çalışır.
Nordes

3

Gönderen https://golang.org/doc/effective_go.html#composite_literals :

Bazen sıfır değeri yeterince iyi değildir ve bu örnekte olduğu gibi os paketinden türetilen bir başlangıç ​​yapıcısı gereklidir.

    func NewFile(fd int, name string) *File {
      if fd < 0 {
        return nil
      }
      f := new(File)
      f.fd = fd
      f.name = name
      f.dirinfo = nil
      f.nepipe = 0
      return f
}

-3
type Config struct {
    AWSRegion                               string `default:"us-west-2"`
}

1
Bu yanlış. En iyi ihtimalle, bu alanda bir etiket değeri ayarlayabilir ve daha sonra yansıma ile değerine erişebilirsiniz, ancak bununla birlikte sözdizimi yanlıştır (geri keneler eksik) ve yalnızca bir dize türü için varsayılan bir değer ayarlayabilirsiniz. Bu örneğin özellikle neyi kastettiğine ilişkin bir fikriniz varsa, lütfen başvurulacak bir bağlantı ekleyin.
markeissler
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.