ZetCode

Go 终端表

最后修改时间 2024 年 4 月 11 日

在本文中,我们将展示如何在 Go 中创建终端表。随着控制台应用程序的复兴,我们寻找一种以整洁格式化的终端表来显示数据的方法。

要使用 Go 创建终端表,我们使用 go-pretty 包。

Go 简单终端表

在第一个示例中,我们创建了一个简单的终端表。

main.go
package main

import (
    "fmt"

    "github.com/jedib0t/go-pretty/v6/table"
)

func main() {

    t := table.NewWriter()
    t.SetCaption("Users")

    t.AppendHeader(table.Row{"#", "Name", "Occupation"})
    t.AppendRow(table.Row{1, "John Doe", "gardener"})
    t.AppendRow(table.Row{2, "Roger Roe", "driver"})
    t.AppendRows([]table.Row{{3, "Paul Smith", "trader"},
        {4, "Lucy Smith", "teacher"}})

    fmt.Println(t.Render())
}

该表有三列和四行。

t := table.NewWriter()

我们使用 NewWriter 创建一个新的表写入器。

t.AppendHeader(table.Row{"#", "Name", "Occupation"})

表头使用 AppendHeader 创建。我们指定了三列的名称。

t.AppendRow(table.Row{1, "John Doe", "gardener"})

使用 AppendRow 添加单行。

t.AppendRows([]table.Row{{3, "Paul Smith", "trader"},
    {4, "Lucy Smith", "teacher"}})

可以使用 AppendRows 一次添加多行。

fmt.Println(t.Render())

使用 Render 渲染表。

$ go run main.go
+---+------------+------------+
| # | NAME       | OCCUPATION |
+---+------------+------------+
| 1 | John Doe   | gardener   |
| 2 | Roger Roe  | driver     |
| 3 | Paul Smith | trader     |
| 4 | Lucy Smith | teacher    |
+---+------------+------------+
Users

在下一个示例中,我们修改了一些东西。

main.go
package main

import (
    "fmt"

    "github.com/jedib0t/go-pretty/v6/table"
    "github.com/jedib0t/go-pretty/v6/text"
)

func main() {

    t := table.NewWriter()
    t.SetTitle("Users")
    t.SetAutoIndex(true)
    t.Style().Format.Header = text.FormatTitle

    t.AppendHeader(table.Row{"Name", "Occupation"})
    t.AppendRow(table.Row{"John Doe", "gardener"})
    t.AppendRow(table.Row{"Roger Roe", "driver"})
    t.AppendRows([]table.Row{{"Paul Smith", "trader"},
        {"Lucy Smith", "teacher"}})

    fmt.Println(t.Render())
}

该示例略有修改。

t.SetTitle("Users")

我们使用 SetTitle 设置表标题,而不是说明。

t.SetAutoIndex(true)

SetAutoIndex 函数会自动创建一个索引列。

t.Style().Format.Header = text.FormatTitle

我们更改了列标题名称的格式。默认情况下,它们显示为大写。

$ go run main.go
+-----------------------------+
| Users                       |
+---+------------+------------+
|   | Name       | Occupation |
+---+------------+------------+
| 1 | John Doe   | gardener   |
| 2 | Roger Roe  | driver     |
| 3 | Paul Smith | trader     |
| 4 | Lucy Smith | teacher    |
+---+------------+------------+

表尾

使用 AppendFooter 添加表尾。

main.go
package main

import (
    "fmt"

    "github.com/jedib0t/go-pretty/v6/table"
    "github.com/jedib0t/go-pretty/v6/text"
)

type User struct {
    Name       string
    Occupation string
    Salary     int
}

func main() {

    users := []User{{"John Doe", "gardener", 1250}, {"Roger Roe", "driver", 950},
        {"Paul Smith", "trader", 2100}, {"Lucy Smith", "teacher", 880}}

    var total int

    for _, u := range users {
        total += u.Salary
    }

    t := table.NewWriter()
    t.SetCaption("Users")
    t.SetAutoIndex(true)
    t.Style().Format.Header = text.FormatTitle
    t.Style().Format.Footer = text.FormatTitle

    t.AppendHeader(table.Row{"Name", "Occupation", "Salary"})

    for _, u := range users {
        t.AppendRow(table.Row{u.Name, u.Occupation, u.Salary})
    }

    t.AppendFooter(table.Row{"", "Total", total})

    fmt.Println(t.Render())
}

我们有一个用户表。每个用户有三个属性:姓名、职业和薪水。我们在表的页脚中添加了总薪水。

type User struct {
    Name       string
    Occupation string
    Salary     int
}

我们定义了 User 结构体。

users := []User{{"John Doe", "gardener", 1250}, {"Roger Roe", "driver", 950},
    {"Paul Smith", "trader", 2100}, {"Lucy Smith", "teacher", 880}}

我们定义了一个用户集合。

for _, u := range users {
    total += u.Salary
}

我们从集合中计算了总薪水金额。

for _, u := range users {
    t.AppendRow(table.Row{u.Name, u.Occupation, u.Salary})
}

我们将数据添加到表中。

t.AppendFooter(table.Row{"", "Total", total})

我们使用 AppendFooter 函数将页脚添加到表中。

$ go run main.go
+---+------------+------------+--------+
|   | Name       | Occupation | Salary |
+---+------------+------------+--------+
| 1 | John Doe   | gardener   |   1250 |
| 2 | Roger Roe  | driver     |    950 |
| 3 | Paul Smith | trader     |   2100 |
| 4 | Lucy Smith | teacher    |    880 |
+---+------------+------------+--------+
|   |            | Total      |   5180 |
+---+------------+------------+--------+
Users

将表写入文件

渲染的表可以轻松地写入文件。

main.go
package main

import (
    "log"
    "os"

    "github.com/jedib0t/go-pretty/v6/table"
    "github.com/jedib0t/go-pretty/v6/text"
)

type User struct {
    Name       string
    Occupation string
    Salary     int
}

func main() {

    f, err := os.Create("data.txt")

    if err != nil {
        log.Fatal(err)
    }

    defer f.Close()

    users := []User{{"John Doe", "gardener", 1250}, {"Roger Roe", "driver", 950},
        {"Paul Smith", "trader", 2100}, {"Lucy Smith", "teacher", 880}}

    t := table.NewWriter()
    t.SetCaption("Users")
    t.SetAutoIndex(true)
    t.Style().Format.Header = text.FormatTitle
    t.SetOutputMirror(os.Stdout)

    t.AppendHeader(table.Row{"Name", "Occupation", "Salary"})

    for _, u := range users {
        t.AppendRow(table.Row{u.Name, u.Occupation, u.Salary})
    }

    f.WriteString(t.Render())
}

在程序中,我们将表写入文件,也写入终端。

f, err := os.Create("data.txt")

if err != nil {
    log.Fatal(err)
}

defer f.Close()

我们创建一个文件,并在其中写入我们的表。

t.SetOutputMirror(os.Stdout)

使用 SetOutputMirror,我们还将数据发送到终端。实际上,数据被写入文件并在控制台中镜像。

f.WriteString(t.Render())

Render 函数返回一个字符串,该字符串使用 WriteString 写入文件。

表样式

该库附带预定义的样式。样式由 table.Style 结构表示。

main.go
package main

import (
    "fmt"

    "github.com/jedib0t/go-pretty/v6/table"
    "github.com/jedib0t/go-pretty/v6/text"
)

type User struct {
    Name       string
    Occupation string
    Salary     int
}

func main() {

    styles := []table.Style{
        table.StyleDefault,
        table.StyleLight,
        table.StyleColoredDark,
        table.StyleColoredBlueWhiteOnBlack,
    }

    users := []User{{"John Doe", "gardener", 1250}, {"Roger Roe", "driver", 950},
        {"Paul Smith", "trader", 2100}, {"Lucy Smith", "teacher", 880}}

    for _, style := range styles {

        t := table.NewWriter()
        t.SetCaption("Users")
        t.AppendHeader(table.Row{"Name", "Occupation", "Salary"})

        for _, u := range users {
            t.AppendRow(table.Row{u.Name, u.Occupation, u.Salary})
        }

        t.SetAutoIndex(true)
        t.SetStyle(style)
        t.Style().Options.SeparateRows = true
        t.Style().Format.Header = text.FormatTitle

        fmt.Println(t.Render())
        fmt.Println()
    }
}

在示例中,我们以各种样式输出表。

styles := []table.Style{
    table.StyleDefault,
    table.StyleLight,
    table.StyleColoredDark,
    table.StyleColoredBlueWhiteOnBlack,
}

我们有一个内置样式的集合。

t.SetStyle(style)

使用 SetStyle 应用样式。

t.Style().Options.SeparateRows = true
t.Style().Format.Header = text.FormatTitle

样式可以在之后通过属性进行修改。

币安订单簿

订单簿是特定资产的买入/买出和卖出/卖出订单的电子列表,按价格水平组织。在我们的示例中,我们展示了币安上 LTC 代币的订单簿。

main.go
package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/adshao/go-binance/v2"
    "github.com/jedib0t/go-pretty/v6/table"
    "github.com/jedib0t/go-pretty/v6/text"
)

func main() {

    var (
        apiKey    = os.Getenv("BINANCE_API_KEY")
        secretKey = os.Getenv("BINANCE_SECRET_KEY")
    )
    client := binance.NewClient(apiKey, secretKey)

    tickers, err := client.NewDepthService().Symbol("LTCBUSD").Limit(15).
        Do(context.Background())

    if err != nil {
        log.Fatal(err)
    }

    // Bids

    t := table.NewWriter()
    t.SetTitle("LTC")
    t.SetCaption("Bids")
    t.SetAutoIndex(true)
    t.SetStyle(table.StyleColoredGreenWhiteOnBlack)
    t.Style().Format.Header = text.FormatTitle
    t.SetColumnConfigs([]table.ColumnConfig{
        {Number: 1, Align: text.AlignRight},
        {Number: 2, Align: text.AlignRight}})

    t.AppendHeader(table.Row{"Price", "Quatity"})

    for _, bid := range tickers.Bids {

        t.AppendRow(table.Row{bid.Price, bid.Quantity})
    }

    fmt.Println(t.Render())

    fmt.Println()

    // Asks

    t2 := table.NewWriter()
    t2.SetTitle("LTC")
    t2.SetCaption("Asks")
    t2.SetAutoIndex(true)
    t2.SetStyle(table.StyleColoredRedWhiteOnBlack)
    t2.Style().Format.Header = text.FormatTitle
    t2.Style().Format.Row = text.Format(text.AlignRight)
    t2.SetColumnConfigs([]table.ColumnConfig{
        {Number: 1, Align: text.AlignRight},
        {Number: 2, Align: text.AlignRight}})

    t2.AppendHeader(table.Row{"Price", "Quatity"})

    for _, ask := range tickers.Asks {

        t2.AppendRow(table.Row{ask.Price, ask.Quantity})
    }

    fmt.Println(t2.Render())
}

该示例创建了两个表:一个用于买单,一个用于卖单。

var (
    apiKey    = os.Getenv("BINANCE_API_KEY")
    secretKey = os.Getenv("BINANCE_SECRET_KEY")
)
client := binance.NewClient(apiKey, secretKey)

我们从币安交易所检索数据。在我们的账户中,我们设置了 API 和 Secret 密钥。

tickers, err := client.NewDepthService().Symbol("LTCBUSD").Limit(15).
    Do(context.Background())

使用 NewDepthService 检索订单簿。我们使用 LTCBUSD 对。

// Bids

t := table.NewWriter()
t.SetTitle("LTC")
t.SetCaption("Bids")
t.SetAutoIndex(true)
t.SetStyle(table.StyleColoredGreenWhiteOnBlack)
t.Style().Format.Header = text.FormatTitle
t.SetColumnConfigs([]table.ColumnConfig{
    {Number: 1, Align: text.AlignRight},
    {Number: 2, Align: text.AlignRight}})

这些是买单。传统上,它们显示为绿色。因此,我们选择了 table.StyleColoredGreenWhiteOnBlack 表样式。我们也已将数据右对齐。

t.AppendHeader(table.Row{"Price", "Quatity"})

每行有两列:价格和数量。

for _, bid := range tickers.Bids {

    t.AppendRow(table.Row{bid.Price, bid.Quantity})
}

fmt.Println(t.Render())

我们遍历买单并将它们添加到表中。之后,该表被渲染到控制台。

t2.SetStyle(table.StyleColoredRedWhiteOnBlack)

对于卖单,我们选择了 table.StyleColoredRedWhiteOnBlack 样式。

for _, ask := range tickers.Asks {

    t2.AppendRow(table.Row{ask.Price, ask.Quantity})
}

fmt.Println(t2.Render())

我们遍历卖单,并将它们添加到第二个表中。最后渲染该表。

来源

Go pretty - Github 页面

在本文中,我们展示了如何在 Go 的终端中生成表。

作者

我叫 Jan Bodnar,是一位热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。迄今为止,我已撰写超过 1400 篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Go 教程