Golang中如何处理CSV读取时单值上下文的多值问题

Golang中如何处理CSV读取时单值上下文的多值问题 尝试从CSV文件中读取datenumber,因此我定义了以下结构体:

type Transaction struct {
	Warehouse string    `json:"warehouse"`
	Item      string    `json:"item"`
	Movement  string    `json:"movement"`
	Batch     string    `json:"batch"`
	Date      time.Time `json:"transaction_data"`
	Quantity  uint64    `json:"quantity"`
}

type Transactions struct {
	header []string
	lines  []Transaction
}

并按以下方式进行读取:

func main() {
	// 读取CSV文件线程 > 开始 //
	pairs := []Pair{{"m", 1}, {"d", 0}, {"c", 2}}
	fmt.Println(pairs)
	// 按键排序
	sort.Sort(ByKey(pairs))
	fmt.Println(pairs)
	pairs = append(pairs, Pair{"h", 5})
	fmt.Println(pairs)

	// 读取CSV文件线程 > 开始 //
	input := make(chan Transactions)
	go func(input_file string) {
		var trx Transactions
		fr, err := os.Open(input_file)
		failOnError(err)
		defer fr.Close()
		r := csv.NewReader(fr)
		rows, err := r.ReadAll()
		failOnError(err)
		trx.header = rows[0]
		for _, row := range rows[1:] {
			trx.lines = append(trx.lines, Transaction{
				Warehouse: strings.TrimSpace(row[0]),
				Item:      strings.TrimSpace(row[1]),
				Movement:  strings.TrimSpace(row[2]),
				Batch:     strings.TrimSpace(row[3]),
				Date:      time.Parse("%Y-%m-%d", row[4]),                   // 单值上下文中的多值错误
				Quantity:  (strconv.ParseFloat(row[5], 64) * 1000).(uint64),  // 单值上下文中的多值错误
			})
		}

		peopleJson, _ := json.Marshal(trx.lines)
		fmt.Println(string(peopleJson)) 

		input <- trx // 将数据发送到通道读取
	}("trx.csv")
	<-input // 从通道'read'接收并赋值给新的数据变量
	// 读取CSV文件线程 < 结束 //
}

然后遇到了两个错误:

.\pair.go:73:24: multiple-value time.Parse() in single-value context
.\pair.go:74:34: multiple-value strconv.ParseFloat() in single-value context

我理解原因,time.Parse()strconv.ParseFloat()都返回两个输出:值和错误。可以通过以下方式解决这个问题:

date, _ := time.Parse("%Y-%m-%d", row[4])
// 然后:
Date:      date,

但我想知道是否可以避免这样做,并在同一个命令块中解决:

trx.lines = append(trx.lines, Transaction{
				Warehouse: strings.TrimSpace(row[0]),
				Item:      strings.TrimSpace(row[1]),
				Movement:  strings.TrimSpace(row[2]),
				Batch:     strings.TrimSpace(row[3]),
				Date:      ...
                Quantity:  ...
}

更多关于Golang中如何处理CSV读取时单值上下文的多值问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复
for _, row := range rows[1:] {
	date, err := time.Parse("2006-01-02", row[4])
	failOnError(err)
	f, err := strconv.ParseFloat(row[5], 64)
	failOnError(err)
	trx.lines = append(trx.lines, Transaction{
		Warehouse: strings.TrimSpace(row[0]),
		Item:      strings.TrimSpace(row[1]),
		Movement:  strings.TrimSpace(row[2]),
		Batch:     strings.TrimSpace(row[3]),
		Date:      date,
		Quantity:  (f * 1000).(uint64),
	})
}

我会这样做。另一种方法是创建一个闭包:

parseDate := func(v string) time.Time {
	t, err := time.Parse("2006-01-02", v)
	failOnError(err)
	return t
}

// ...
Date: parseDate(row[4])
// ...

更多关于Golang中如何处理CSV读取时单值上下文的多值问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中,当函数返回多个值时,不能直接在结构体字面量中使用这些函数。不过,你可以通过以下几种方式在同一个代码块中处理:

方案1:使用匿名函数(立即执行)

trx.lines = append(trx.lines, Transaction{
    Warehouse: strings.TrimSpace(row[0]),
    Item:      strings.TrimSpace(row[1]),
    Movement:  strings.TrimSpace(row[2]),
    Batch:     strings.TrimSpace(row[3]),
    Date: func() time.Time {
        t, _ := time.Parse("2006-01-02", row[4])
        return t
    }(),
    Quantity: func() uint64 {
        f, _ := strconv.ParseFloat(row[5], 64)
        return uint64(f * 1000)
    }(),
})

方案2:使用辅助函数

func parseDate(s string) time.Time {
    t, _ := time.Parse("2006-01-02", s)
    return t
}

func parseQuantity(s string) uint64 {
    f, _ := strconv.ParseFloat(s, 64)
    return uint64(f * 1000)
}

// 在循环中使用
trx.lines = append(trx.lines, Transaction{
    Warehouse: strings.TrimSpace(row[0]),
    Item:      strings.TrimSpace(row[1]),
    Movement:  strings.TrimSpace(row[2]),
    Batch:     strings.TrimSpace(row[3]),
    Date:      parseDate(row[4]),
    Quantity:  parseQuantity(row[5]),
})

方案3:使用闭包变量(在同一作用域内)

trx.lines = append(trx.lines, func() Transaction {
    date, _ := time.Parse("2006-01-02", row[4])
    quantity, _ := strconv.ParseFloat(row[5], 64)
    
    return Transaction{
        Warehouse: strings.TrimSpace(row[0]),
        Item:      strings.TrimSpace(row[1]),
        Movement:  strings.TrimSpace(row[2]),
        Batch:     strings.TrimSpace(row[3]),
        Date:      date,
        Quantity:  uint64(quantity * 1000),
    }
}())

方案4:使用结构体方法(推荐)

type Transaction struct {
    Warehouse string    `json:"warehouse"`
    Item      string    `json:"item"`
    Movement  string    `json:"movement"`
    Batch     string    `json:"batch"`
    Date      time.Time `json:"transaction_data"`
    Quantity  uint64    `json:"quantity"`
}

func NewTransactionFromCSV(row []string) Transaction {
    date, _ := time.Parse("2006-01-02", row[4])
    quantity, _ := strconv.ParseFloat(row[5], 64)
    
    return Transaction{
        Warehouse: strings.TrimSpace(row[0]),
        Item:      strings.TrimSpace(row[1]),
        Movement:  strings.TrimSpace(row[2]),
        Batch:     strings.TrimSpace(row[3]),
        Date:      date,
        Quantity:  uint64(quantity * 1000),
    }
}

// 在循环中使用
trx.lines = append(trx.lines, NewTransactionFromCSV(row))

方案5:使用错误处理(完整版本)

func NewTransactionFromCSV(row []string) (Transaction, error) {
    date, err := time.Parse("2006-01-02", row[4])
    if err != nil {
        return Transaction{}, fmt.Errorf("parse date: %w", err)
    }
    
    quantity, err := strconv.ParseFloat(row[5], 64)
    if err != nil {
        return Transaction{}, fmt.Errorf("parse quantity: %w", err)
    }
    
    return Transaction{
        Warehouse: strings.TrimSpace(row[0]),
        Item:      strings.TrimSpace(row[1]),
        Movement:  strings.TrimSpace(row[2]),
        Batch:     strings.TrimSpace(row[3]),
        Date:      date,
        Quantity:  uint64(quantity * 1000),
    }, nil
}

// 在循环中使用
transaction, err := NewTransactionFromCSV(row)
if err != nil {
    // 处理错误
    continue
}
trx.lines = append(trx.lines, transaction)

注意:你的代码中时间格式字符串有误,应该是 "2006-01-02" 而不是 "%Y-%m-%d",这是Go语言特定的时间格式。

回到顶部