Привет, мы создаем новый язык выражений для управления структурными данными Golang. Код проекта размещен на https://github.com/lysu/go-el.

Его основная цель - найти Reflect.Value по выражению, а затем прочитать и написать. Это очень полезно для создания HTTP Patch API.

Установка

Просто, как это требуется, чтобы ввести следующую команду:

go get github.com/lysu/go-el

и импортировать с

import github.com/lysu/go-el

использование

Пример данных

Например, у нас есть такие данные:

type Comment struct {
    NickName string
    Content  string
    Date     time.Time
}
type Author struct {
  Name string
}
type Blog struct {
    Title      string
    RoleState  map[string]uint
    CommentIds []uint64
    Comments   map[string]*Comment
}
func (b Blog) FirstComment() *Comment {
    return b.Comments["0"]
}

затем мы инициализируем их некоторыми тестовыми данными:

b := &Blog{
  Title:      "Blog title1",
  CommentIds: []uint64{1, 3},
  Comments: map[string]*Comment{
    "0": {
      NickName: "000",
      Content:  "test",
      Date:     time.Now(),
    },
    "1": {
      NickName: "u1",
      Content:  "test",
      Date:     time.Now(),
    },
    "3": {
      NickName: "tester",
      Content:  "test hehe...",
      Date:     time.Now(),
    },
  },
  Author: Author{
      Name: "Author 1",
  },
  RoleState: map[string]uint{},
}

Выражение

Используя el.Expression, мы можем перейти от root(b) к любому месту в этой структуре.

1. В поле

exp := el.Expression("Title")
v, _ := exp.Execute(&data)
fmt.Printf("%v\n", v.interface()) //==> Blog title1

2. Во вложенное поле

exp := el.Expression("Author.Name")
v, _ := exp.Execute(&data)
fmt.Printf("%v\n", v.interface()) //==> Author 1

3. Чтобы нарезать/массив/строковый элемент

exp := el.Expression("CommentIds[0]")
v, _ := exp.Execute(&data)
fmt.Printf("%v\n", v.interface()) //==> 1

4. Чтобы сопоставить элемент

exp := el.Expression("Comments["3"].NickName")
v, _ := exp.Execute(&data)
fmt.Printf("%v\n", v.interface()) //==> tester

5. Элемент в [] также может быть другим выражением

exp := el.Expression("Comments[CommentIds[0]].NickName")
v, _ := exp.Execute(&data)
fmt.Printf("%v\n", v.interface()) //==> u1

6. Функция вызова

функция может вернуть только ОДИН результат

exp := el.Expression("FirstComment().Content")
v, _ := exp.Execute(&data)
fmt.Printf("%v\n", v.interface()) //==> test

7. Изменить значение

После выражения Execute мы получили relfect.Value, мы также можем использовать его для изменения данных, например.

exp := el.Expression("FirstComment().Content")
v, _ := exp.Execute(&data)
v.SetString("1111")

позволит первому комментарию со значением 1111

Кроме того, мы рекомендуем пользователям уделить время просмотру Законов отражения, позаботиться о некоторых ограничениях, которые имеет отражение.

Патчер

Основываясь на Expression, мы также предоставляем инструмент под названием Patcher, цель которого — упростить использование изменения объекта с выражением и его пакетную обработку.

Мы обнаружили, что очень полезно создать HTTP Patch API для частичного обновления объекта.

ps := p.Patch{
  "Author.Name":                      "ほん",
  "Comments[CommentIds[0]].NickName": "私",
  "roleState[100]":                   uint(100),
}
err := patcher.PatchIt(b, ps)

Это изменит сразу три свойства~ (но мы по-прежнему соблюдаем некоторые правила refect, такие как использование значения карты ptr.. и т. д.)

Более

См. наш пример в Unit-Test:

СДЕЛАТЬ

генерировать выражение между двумя данными.. как diff..- -?

Спасибо