如何在忽略空字符串的情况下连接结构的字符串字段?

时间:2019-07-18 12:07:42

标签: go string-concatenation

我对Go真的很陌生,所以需要一些建议。 我有一个结构:

type Employee struct {
    Name        string
    Designation string
    Department  string
    Salary      int
    Email       string
}

我想将字符串字段连接成一种员工描述。 因此,我可以说: toString(employee)并获得:

John Smith Manager Sales john.smith@example.com

我试图获取每个字段,检查它们是否为空并将它们切成薄片并在最后加入它们

employeeDescArr := make([]string, 0, 4)
if strings.TrimSpace(value) != "" {
    append(employee.GetName(), value)
}...
return strings.Join(employeeDescArr[:], " ")

我认为这种方法非常冗长,显示出缺乏围棋技巧。 改用字符串生成器更好吗? 有没有一种方法可以以反射的方式遍历结构的所有字段并加入它们?

4 个答案:

答案 0 :(得分:1)

遍历字符串字段并收集非空字符串。加入领域。

func (e *Employee) String() string {
    var parts []string
    for _, s := range []string{e.Name, e.Designation, e.Department, e.Email} {
        if strings.TrimSpace(s) != "" {
            parts = append(parts, s)
        }
    }
    return strings.Join(parts, " ")
}

因为strings.Join函数是使用strings.Builder实现的,所以替换字符串没有任何好处。使用使用strings.Builder的应用程序代码进行联接。

以下是使用反射来避免在字符串函数中列出字段的方法:

var stringType = reflect.TypeOf("")

func (e *Employee) String() string {
    v := reflect.ValueOf(e).Elem()
    var parts []string
    for i := 0; i < v.NumField(); i++ {
        f := v.Field(i)
        if f.Type() == stringType {
            s := f.String()
            if strings.TrimSpace(s) != "" {
                parts = append(parts, s)
            }
        }
    }
    return strings.Join(parts, " ")
}

如果要包括所有字段(包括非字符串和空字符串),则可以fmt.Sprint(e)来获取字符串。参见https://play.golang.org/p/yntZxQ-Xs6C

答案 1 :(得分:0)

您可以通过编写实用程序功能以使附加项带有“非空白字符串”检查来使它变得不那么冗长。

此外,您可以使类型实现实现String()方法,该方法的优点是可以在fmt打印功能中使用时按需要打印。

addToString函数是通用的,因此如果对其他类型执行此操作,则可以重用它:

func addToString(original string, addition interface{}) string {
    additionStr := fmt.Sprint(addition)
    if additionStr != "" {
        if original != "" {
            original += " "
        }
        original += additionStr
    }
    return original
}

然后您可以像这样实现它,它并不那么冗长:

type Employee struct {
    Name        string
    Designation string
    Department  string
    Salary      int
    Email       string
}

func (e *Employee) String() string {
    theString := ""
    theString = addToString(theString, e.Name)
    theString = addToString(theString, e.Designation)
    theString = addToString(theString, e.Department)
    theString = addToString(theString, e.Salary)
    theString = addToString(theString, e.Email)
    return theString
}

并像这样使用它:

func main() {
    emp := &Employee{
        Name: "Jonh",
        Department: "Some dept",
    }
    fmt.Println(emp.String())
    fmt.Println(emp)
}

哪个会输出:

Jonh Some dept 0
Jonh Some dept 0

答案 2 :(得分:0)

我认为您想改用Stringer接口。即:

package main

import (
  "fmt"
  "strings"
  "strconv"
)
type Employee struct {
    Name        string
    Designation string
    Department  string
    Salary      int
    Email       string
}
func main() {
  emp1:=Employee{Name:"Cetin", Department:"MS", Salary:50}
  emp2:=Employee{Name:"David", Designation:"Designation", Email:"david@nowhere.com"}
  emp3:=Employee{Department:"Space", Salary:10}

  fmt.Println(emp1)
  fmt.Println(emp2)
  fmt.Println(emp3)

}

func (e Employee) String() string {
    var salary string
    if e.Salary > 0 { 
      salary = strconv.Itoa(e.Salary) + " " 
    } else {
      salary = ""
    }
    return strings.TrimSpace(
        strings.TrimSpace(
        strings.TrimSpace(e.Name + " " + e.Designation) + " " +
        e.Department) + " " +
    salary +
        e.Email)
}

游乐场:https://play.golang.org/p/L8ft7SeXpqt

PS:我后来发现您只希望使用字符串字段,但无论如何都没有删除薪水。

答案 3 :(得分:0)

  

Package fmt

import "fmt" 
     

type Stringer

     

Stringer由具有String方法的任何值实现,   定义该值的“本机”格式。使用String方法   打印作为操作数传递的值,使其接受任何格式   字符串或未格式化的打印机(例如“打印”)。

type Stringer interface {
        String() string
}

为类型String写一个Employee方法。

例如,

package main

import (
    "fmt"
    "strings"
)

type Employee struct {
    Name        string
    Designation string
    Department  string
    Salary      int
    Email       string
}

func appendItem(items *strings.Builder, item string) {
    if len(item) > 0 {
        if items.Len() > 0 {
            items.WriteByte(' ')
        }
        items.WriteString(item)
    }
}

func (e Employee) String() string {
    s := new(strings.Builder)
    appendItem(s, e.Name)
    appendItem(s, e.Designation)
    appendItem(s, e.Department)
    appendItem(s, e.Email)
    return s.String()
}

func main() {
    ee := Employee{
        Name:        "John Smith",
        Designation: "Manager",
        Department:  "Sales",
        Email:       "john.smith@example.com",
        Salary:      42000,
    }
    fmt.Println(ee)
}

游乐场:https://play.golang.org/p/EPBjgi8usJ-

输出:

John Smith Manager Sales john.smith@example.com

  

我想将字符串字段连接成一种雇员   说明。

     

是否有一种方法可以遍历一个结构体的所有字段   反思方式并加入他们?

[反射是]功能强大的工具,应谨慎使用,除非绝对必要,否则应避免使用。罗伯·派克

The Go Blog: The Laws of Reflection

反射永远不清楚。罗伯·派克

Go Proverbs - Rob Pike - Gopherfest - November 18, 2015

Go编译后的代码非常有效。 Go反射包功能在运行时进行解释。

遍历结构的所有字段与SQL中的SELECT * FROM table;具有相同的错误。返回的值是在运行时而不是编译时确定的。

如果是您的情况,业务要求是隐藏机密字段(例如薪水),并将显示的字段限制为几个关键的描述性字段。不可避免地,字段将被添加到结构中。 “连接字符串字段”规范现在或将来都不太可能正确。