Golang实现子节点包含不同数据类型的树结构(类似JSON但强类型)

Golang实现子节点包含不同数据类型的树结构(类似JSON但强类型) 我有一个网页表单,希望用Go语言将其表示为各种类型的树结构。

在Go语言中,用什么惯用方式能有效实现这个需求?

节点类型包括:

  • 根节点(表单本身)
  • 页面(多页表单中的页面)
  • 区域
  • 具体输入字段(文本输入框、复选框等)
  • 条件字段和区域(包含引用其他字段/区域的公式;评估为TRUE或FALSE后,将在表单渲染时控制字段的显示/隐藏状态)
  • 可重复字段(例如,当受访者可以点击"添加城市"按钮并多次输入更多城市时)
1 回复

更多关于Golang实现子节点包含不同数据类型的树结构(类似JSON但强类型)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中,实现这种包含不同数据类型子节点的树结构,推荐使用接口(interface)和类型断言(type assertion)的惯用方式。以下是一个完整的实现示例:

package main

import (
    "fmt"
)

// 定义节点接口
type Node interface {
    Name() string
    Children() []Node
    AddChild(Node)
}

// 基础节点结构,嵌入到具体节点类型中
type BaseNode struct {
    name     string
    children []Node
}

func (b *BaseNode) Name() string {
    return b.name
}

func (b *BaseNode) Children() []Node {
    return b.children
}

func (b *BaseNode) AddChild(child Node) {
    b.children = append(b.children, child)
}

// 根节点(表单)
type FormNode struct {
    BaseNode
    Title string
}

func NewFormNode(title string) *FormNode {
    return &FormNode{
        BaseNode: BaseNode{name: "form"},
        Title:    title,
    }
}

// 页面节点
type PageNode struct {
    BaseNode
    PageNumber int
}

func NewPageNode(name string, pageNumber int) *PageNode {
    return &PageNode{
        BaseNode:   BaseNode{name: name},
        PageNumber: pageNumber,
    }
}

// 区域节点
type SectionNode struct {
    BaseNode
    Description string
}

func NewSectionNode(name, description string) *SectionNode {
    return &SectionNode{
        BaseNode:    BaseNode{name: name},
        Description: description,
    }
}

// 文本输入字段
type TextInputNode struct {
    BaseNode
    Label       string
    Placeholder string
    Required    bool
}

func NewTextInputNode(name, label, placeholder string, required bool) *TextInputNode {
    return &TextInputNode{
        BaseNode:    BaseNode{name: name},
        Label:       label,
        Placeholder: placeholder,
        Required:    required,
    }
}

// 复选框字段
type CheckboxNode struct {
    BaseNode
    Label   string
    Checked bool
}

func NewCheckboxNode(name, label string, checked bool) *CheckboxNode {
    return &CheckboxNode{
        BaseNode: BaseNode{name: name},
        Label:    label,
        Checked:  checked,
    }
}

// 条件字段
type ConditionalNode struct {
    BaseNode
    Condition string
    IsVisible bool
}

func NewConditionalNode(name, condition string) *ConditionalNode {
    return &ConditionalNode{
        BaseNode:  BaseNode{name: name},
        Condition: condition,
        IsVisible: true,
    }
}

// 可重复字段组
type RepeatableNode struct {
    BaseNode
    MaxRepeats int
    ItemCount  int
}

func NewRepeatableNode(name string, maxRepeats int) *RepeatableNode {
    return &RepeatableNode{
        BaseNode:   BaseNode{name: name},
        MaxRepeats: maxRepeats,
        ItemCount:  1,
    }
}

// 遍历树的工具函数
func TraverseTree(node Node, level int) {
    indent := ""
    for i := 0; i < level; i++ {
        indent += "  "
    }
    
    fmt.Printf("%s%s", indent, node.Name())
    
    // 类型断言获取具体类型信息
    switch n := node.(type) {
    case *FormNode:
        fmt.Printf(" (表单: %s)", n.Title)
    case *PageNode:
        fmt.Printf(" (页面 %d)", n.PageNumber)
    case *SectionNode:
        fmt.Printf(" (区域: %s)", n.Description)
    case *TextInputNode:
        fmt.Printf(" (文本输入: %s, 必填: %t)", n.Label, n.Required)
    case *CheckboxNode:
        fmt.Printf(" (复选框: %s, 选中: %t)", n.Label, n.Checked)
    case *ConditionalNode:
        fmt.Printf(" (条件: %s, 可见: %t)", n.Condition, n.IsVisible)
    case *RepeatableNode:
        fmt.Printf(" (可重复: 最大%d次)", n.MaxRepeats)
    }
    fmt.Println()
    
    for _, child := range node.Children() {
        TraverseTree(child, level+1)
    }
}

func main() {
    // 创建表单树结构
    form := NewFormNode("用户注册表单")
    
    // 第一页
    page1 := NewPageNode("基本信息", 1)
    form.AddChild(page1)
    
    // 个人信息区域
    personalSection := NewSectionNode("个人信息", "填写个人基本信息")
    page1.AddChild(personalSection)
    
    // 添加字段
    nameField := NewTextInputNode("name", "姓名", "请输入姓名", true)
    emailField := NewTextInputNode("email", "邮箱", "请输入邮箱", true)
    personalSection.AddChild(nameField)
    personalSection.AddChild(emailField)
    
    // 条件字段
    newsletterField := NewConditionalNode("newsletter", "email != ''")
    newsletterCheckbox := NewCheckboxNode("subscribe", "订阅新闻", false)
    newsletterField.AddChild(newsletterCheckbox)
    personalSection.AddChild(newsletterField)
    
    // 可重复字段组
    citiesGroup := NewRepeatableNode("cities", 5)
    cityField := NewTextInputNode("city", "居住城市", "输入城市名称", false)
    citiesGroup.AddChild(cityField)
    personalSection.AddChild(citiesGroup)
    
    // 遍历显示树结构
    TraverseTree(form, 0)
}

这个实现提供了以下特性:

  1. 类型安全:每个节点类型都有明确的字段定义
  2. 可扩展性:可以轻松添加新的节点类型
  3. 树形遍历:通过统一的接口可以遍历整个结构
  4. 条件逻辑:条件节点可以包含显示/隐藏逻辑
  5. 重复结构:可重复节点支持动态添加项目

输出示例:

form (表单: 用户注册表单)
  基本信息 (页面 1)
    个人信息 (区域: 填写个人基本信息)
      姓名 (文本输入: 姓名, 必填: true)
      邮箱 (文本输入: 邮箱, 必填: true)
      新闻订阅 (条件: email != '', 可见: true)
        订阅新闻 (复选框: 订阅新闻, 选中: false)
      城市组 (可重复: 最大5次)
        居住城市 (文本输入: 居住城市, 必填: false)

这种实现方式既保持了Go语言的类型安全特性,又提供了类似JSON的灵活树形结构。

回到顶部