среда, 23 января 2019 г.

Эффективный Go: конструкторы и составные литералы

Иногда нулевое значение, возвращаемое при аллокации с помощью оператора new, недостаточно хорошо и инициализационный конструктор необходим, в следующем примере он получен из пакета os.

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
}

Здесь выполняется много подготовительной однообразной работы. Мы можем упростить это используя составной литерал (composite literal), который является выражением, которое создает новый экземпляр каждый раз, когда он оценивается.

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

Обратите внимание, что, в отличие от C, вполне нормально возвращать адрес локальной переменной; хранилище, связанное с переменной, сохраняется после возврата из функции. На самом деле, взятие адреса составного литерала выделяет новый экземпляр каждый раз, когда он оценивается, поэтому мы можем объединить эти две последние строки.

return &File{fd, name, nil, 0}

Поля составного литерала расположены по порядку и должны присутствовать. Однако, пометив элементы явно как field:value пары, инициализаторы могут появляться в любом порядке, с пропуском каких-либо из них, оставленных в виде соответствующих им нулевых значений. Таким образом, мы могли бы сказать,

return &File{fd: fd, name: name}

В качестве предельного случая, если составной литерал вообще не содержит полей, он создает нулевое значение для типа. Выражения new(File) и &File{} эквивалентны.

Составные литералы также могут быть созданы для массивов, срезов и карт, с метками полей, являющимися индексами или ключами карты в зависимости от ситуации. В следующем примере инициализация работает независимо от значений Enone, Eio и Einval, если они различны.

a := [...]string   {Enone: "no error", Eio: "Eio", 
                    Einval: "invalid argument"}
s := []string      {Enone: "no error", Eio: "Eio", 
                    Einval: "invalid argument"}
m := map[int]string{Enone: "no error", Eio: "Eio", 
                    Einval: "invalid argument"}


Читайте также:


Комментариев нет:

Отправить комментарий