Golang обновить поле структуры внутри функции, переданной как интерфейс - PullRequest
1 голос
/ 30 сентября 2019

Я новичок (Голанг). Вот почему мой вопрос может быть неуместным (или невозможным ответить).

Я создал две структуры. Оба из них встраивают другую структуру. Теперь я хочу обновить поле встроенной структуры внутри функции.

package main

import (
    "fmt"
    "reflect"
    "time"
)

type Model struct {
    UpdatedAt time.Time
}

type Fruit struct {
    Model
    label string
}

type Animal struct {
    Model
    label string
}

func update(v interface{}) {
    reflectType := reflect.TypeOf(v)
    reflectKind := reflectType.Kind()
    if reflectKind == reflect.Ptr {
        reflectType = reflectType.Elem()
    }
    m := reflect.Zero(reflectType)
    fmt.Println(m)
}

func main() {
    apple := &Fruit{
        label: "Apple",
    }
    tiger := &Animal{
        label: "Tiger",
    }
    update(apple)
    update(tiger)
    fmt.Println(apple)
    fmt.Println(tiger)
}

Я хочу реализовать функцию update, чтобы она поместила текущее время в UpdatedAt переданной структуры. Но я не могу этого сделать.

В этом случае поля Fruit и Animal одинаковы: label. Но так будет не всегда. Пожалуйста, имейте это в виду при предоставлении ваших предложений.

Любые рекомендации будут высоко оценены.

Ответы [ 2 ]

4 голосов
/ 30 сентября 2019

Я бы избегал reflect или interface{}, если вы начинаете учиться, иди. Начинающие обычно отступают от них как void * костыль. Попробуйте использовать конкретные типы или четко определенные интерфейсы.

Это должно помочь вам:

type Timestamper interface {
    Update()
    UpdatedTime() time.Time
}

type Model struct {
    updated time.Time
}

func (m *Model) Update()                { m.updated = time.Now() }
func (m *Model) UpdatedTime() time.Time { return m.updated }

type Fruit struct {
    Model
    label string
}

type Animal struct {
    Model
    label string
}

// update will work with a `Model` `Animal` or `Fruit`
// as they all implement the `Timestamper` interface`
func update(v Timestamper) {
    v.Update()
}

Детская площадка: https://play.golang.org/p/27yDVLr-zqd

3 голосов
/ 30 сентября 2019

Предполагая, что вы хотите достичь этого с помощью отражения: прежде всего, вы должны передать указатель на структуру. Теперь вы передаете копию структуры, поэтому любые изменения, сделанные в update, будут выполнены для копии, а не для экземпляра, в который вы были переданы. Затем вы можете найти поле UpdatedAt в переданном интерфейсе,и установите его.

Тем не менее, это, вероятно, не лучший способ сделать это. Другой способ сделать это без отражения:

func update(in *Model) {
   in.UpdatedAt = time.Now()
}

func main() {
   apple := &Fruit{}
   update(&apple.Model)
}

Или:

func (in *Model) update() {
   in.UpdatedAt = time.Now()
}

func main() {
   apple := &Fruit{}
   apple.update()
}
...