Golang中空字段的惯用扫描方法
Golang中空字段的惯用扫描方法 是否存在一种惯用方法来扫描包含空字段的字符串?
具体来说…
这个小例子运行正常:https://play.golang.org/p/VrQtKqtorFi
但如果目标字符串包含空字段,比如这样(注意开头的字段现在是空的):
target := ";1;1551121142780;303421;26.70921316;true"
那么我会得到
panic: strconv.ParseFloat: parsing “”: invalid syntax
因为 strconv 无法解析空字符串。
我应该创建一个带有.Scan方法的自定义"Float"对象,还是有更直接的方法?
谢谢!
更多关于Golang中空字段的惯用扫描方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
问题似乎出在 Scanf 上。 这样写可以正常工作:
s, _:= strconv.ParseFloat("", 32)
fmt.Println(s)
感谢Yamil,但在你的示例中,ParseFloat实际上抛出了同样的错误。你的代码只是没有检查错误,所以返回的零值看起来是正确的:以下是错误信息
package main
import (
"fmt"
"strconv"
)
func main() {
s, err := strconv.ParseFloat("", 32)
fmt.Println(s, err)
}
可以这样做:https://goplay.space/#cG7oZD_co3C 虽然需要多写一些代码,但如果你能接受默认值(0和0.0),就可以忽略strconv函数返回的错误。
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
target := ";1;155142780;303421;26.70921316;true"
fields := strings.Split(target, ";")
scale, _ := strconv.ParseFloat(fields[0], 32)
size, _ := strconv.ParseInt(fields[1], 0, 64)
stamp, _ := strconv.ParseInt(fields[2], 0, 64)
count, _ := strconv.ParseInt(fields[3], 0, 64)
fmt.Printf("Scale:%f Size:%d Stamp:%d Count:%d\n", scale, size, stamp, count)
}
在Go中处理包含空字段的字符串扫描时,确实有几种惯用方法。最直接的方式是使用strings.Split()结合条件检查来处理空值,而不是依赖单一的fmt.Sscanf()。
以下是处理这种情况的示例代码:
package main
import (
"fmt"
"strconv"
"strings"
)
type Record struct {
Field1 string
Field2 int
Field3 int64
Field4 int
Field5 float64
Field6 bool
}
func parseRecord(data string) (*Record, error) {
parts := strings.Split(data, ";")
if len(parts) != 6 {
return nil, fmt.Errorf("invalid number of fields: %d", len(parts))
}
record := &Record{}
// Field1 (string) - 直接赋值,空字符串就是空字符串
record.Field1 = parts[0]
// Field2 (int) - 处理空字符串
if parts[1] != "" {
val, err := strconv.Atoi(parts[1])
if err != nil {
return nil, fmt.Errorf("invalid Field2: %w", err)
}
record.Field2 = val
}
// Field3 (int64) - 处理空字符串
if parts[2] != "" {
val, err := strconv.ParseInt(parts[2], 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid Field3: %w", err)
}
record.Field3 = val
}
// Field4 (int) - 处理空字符串
if parts[3] != "" {
val, err := strconv.Atoi(parts[3])
if err != nil {
return nil, fmt.Errorf("invalid Field4: %w", err)
}
record.Field4 = val
}
// Field5 (float64) - 处理空字符串
if parts[4] != "" {
val, err := strconv.ParseFloat(parts[4], 64)
if err != nil {
return nil, fmt.Errorf("invalid Field5: %w", err)
}
record.Field5 = val
}
// Field6 (bool) - 处理空字符串
if parts[5] != "" {
val, err := strconv.ParseBool(parts[5])
if err != nil {
return nil, fmt.Errorf("invalid Field6: %w", err)
}
record.Field6 = val
}
return record, nil
}
func main() {
target := ";1;1551121142780;303421;26.70921316;true"
record, err := parseRecord(target)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Field1: '%s'\n", record.Field1)
fmt.Printf("Field2: %d\n", record.Field2)
fmt.Printf("Field3: %d\n", record.Field3)
fmt.Printf("Field4: %d\n", record.Field4)
fmt.Printf("Field5: %f\n", record.Field5)
fmt.Printf("Field6: %t\n", record.Field6)
}
另一种更简洁的方法是使用指针类型和辅助函数:
package main
import (
"fmt"
"strconv"
"strings"
)
type Record struct {
Field1 *string
Field2 *int
Field3 *int64
Field4 *int
Field5 *float64
Field6 *bool
}
func parseOptionalInt(s string) (*int, error) {
if s == "" {
return nil, nil
}
val, err := strconv.Atoi(s)
if err != nil {
return nil, err
}
return &val, nil
}
func parseOptionalFloat(s string) (*float64, error) {
if s == "" {
return nil, nil
}
val, err := strconv.ParseFloat(s, 64)
if err != nil {
return nil, err
}
return &val, nil
}
func parseOptionalBool(s string) (*bool, error) {
if s == "" {
return nil, nil
}
val, err := strconv.ParseBool(s)
if err != nil {
return nil, err
}
return &val, nil
}
func parseRecord(data string) (*Record, error) {
parts := strings.Split(data, ";")
if len(parts) != 6 {
return nil, fmt.Errorf("invalid number of fields: %d", len(parts))
}
record := &Record{}
// Field1
if parts[0] != "" {
record.Field1 = &parts[0]
}
// Field2
field2, err := parseOptionalInt(parts[1])
if err != nil {
return nil, fmt.Errorf("invalid Field2: %w", err)
}
record.Field2 = field2
// Field3
if parts[2] != "" {
val, err := strconv.ParseInt(parts[2], 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid Field3: %w", err)
}
record.Field3 = &val
}
// Field4
field4, err := parseOptionalInt(parts[3])
if err != nil {
return nil, fmt.Errorf("invalid Field4: %w", err)
}
record.Field4 = field4
// Field5
field5, err := parseOptionalFloat(parts[4])
if err != nil {
return nil, fmt.Errorf("invalid Field5: %w", err)
}
record.Field5 = field5
// Field6
field6, err := parseOptionalBool(parts[5])
if err != nil {
return nil, fmt.Errorf("invalid Field6: %w", err)
}
record.Field6 = field6
return record, nil
}
func main() {
target := ";1;1551121142780;303421;26.70921316;true"
record, err := parseRecord(target)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Field1: %v\n", record.Field1)
fmt.Printf("Field2: %v\n", record.Field2)
fmt.Printf("Field3: %v\n", record.Field3)
fmt.Printf("Field4: %v\n", record.Field4)
fmt.Printf("Field5: %v\n", record.Field5)
fmt.Printf("Field6: %v\n", record.Field6)
}
第一种方法使用零值表示空字段,第二种方法使用指针来明确区分空值和零值。这两种都是Go中处理这种情况的惯用方法。

