Публични полета и методи на неекспортнати структури

  1. Здравейте,

    Има ли use case за създаването на публични полета и методи, когато една структура не е експортната?

    Давам пример:

    package geometry
    
    type rectangle struct {
        Height, Width int
    }
    
    func (r *rectangle) Area() float64 {
        return float64(r.Height * r.Width)
    }
    
    func (r *rectangle) Circumference() int {
        return 2 * (r.Height + r.Width)
    }
    

    В случая - структурата rectangle не е експортната и ще се вижда само в пакета geometry.

    Според мен, ако една структура не е експортната, то по начало "външния свят" (други пакети) няма как да я намерят и използват, което прави безсмислено всякакво експортване на нейно поле или метод.

    Ако наистна няма use case-и, следсвтие ли е, че ако структура не е експортната, то по-добре и полетата и методите й да не са (най-малкото от съображение за консистентност в кода)? Има ли някакви конвенции по този въпрос?

  2. Наистина има случаи, когато искаш експортнати полета на не-експортнат тип. От раз се сещам за JSON/XML/дурги кодиране и разкодиране. Пакетите в стандартната библиотека работят с експортнати полета на структурите. Ако вземем JSON за конкретен пример, можеш да видиш тази статия в блога и документацията на json.Marshal. Обърни внимание на описанието на "struct field tags". Така работят и останалите видове кодирания. Така че ако искаш да правиш това с типа ти, дори и това да е само в твоя пакет, то ще са ти необходими експортнати полета.

  3. Ясно. Има логика в такива случаи (за field tags).

    В действителност се сетих, че може да има и следната ситуация:

    package editor
    
    type Editor interface {
        Insert(position uint, text string) Editor
    
        Delete(offset, length uint) Editor
    
        Undo() Editor
    
        Redo() Editor
    
        String() string
    }
    
    type defaultEditor struct {
        // fields
    }
    
    func NewDefaultEditor() *defaultEditor {
        editor:= &defaultEditor{}
    
        /* 
          ...
          configure editor
          ...
        */ 
    
        return editor
    }
    

    Тук defaultEditor може да има някакви експортнати полета/методи, които след викане на NewDefaultEditor (от друг пакет) да използваме.

    Приемаме, че defaultEditor имплементира Editor. Просто исках да спестя код. :)

  4. В твоя пример потребителите от други пакети ще имат достъп само до методите на интерфейса. Няма да имат достъп до никакви полета които defaultEditor има. Екпортнати или не.

  5. О, не съм видял как в твоя пример NewDefaultEditor връща defaultEditor, а не Editor. Определено недей да правиш това в твоите програми. Освен ако не искаш да проведеш експеримент "как да накарам възможно най - много хора да си мислят лоши неща за мен". За част от обяснението виж секцията "Generality" от EffectiveGo. Другата причина е, че така потребителите на твоя пакет няма да знаят как да използват стойността върната от NewDefaultEditor тъй като нямат документация за нея. Единственият им шанс би бил да прочетат кода на твоя пакет и някак си сами да се сетят, че отговаря на Editor интерфейса. Последното не е тривиално.

Трябва да сте влезли в системата, за да може да отговаряте на теми.