Append string to string builder passed to a method and return updated string builder back?

Issue

I am transitioning from C# to Golang and I am trying to do things what used to work in C#. I am trying to populate resourceBuilder string builder by appending string to it.

But I am passing resourceBuilder string builder to AppendResource method and appending strings to the same string builder passed to AppendResource method but when the call comes back to Build method, I don’t see it has everything appended to it. I am sure something wrong I am doing but I cannot figure it out.

func Build(queryMap map[string][]QueryFilter, clientId int64, template []string) string {
    var resourceBuilder strings.Builder
    for _, propertyName := range template {
        queryFilters := queryMap[propertyName]
        AppendResource(queryFilters, resourceBuilder)
    }
    fmt.Println("output: ", resourceBuilder.String())
    return resourceBuilder.String()
}

func AppendResource(resourcesOpt []QueryFilter, resourceBuilder strings.Builder) {
    for _, qf := range resourcesOpt {
        if len(resourceBuilder.String()) == 0 {
            resourceBuilder.WriteString(qf.Resource.ResourceType)
            resourceBuilder.WriteString("-")
            resourceBuilder.WriteString(strconv.Itoa(qf.Resource.ResourceId))
        } else {
            resourceBuilder.WriteString("+")
            resourceBuilder.WriteString(qf.Resource.ResourceType)
            resourceBuilder.WriteString("-")
            resourceBuilder.WriteString(strconv.Itoa(qf.Resource.ResourceId))
        }
    }
}

If I do same thing in C# then resourceBuilder string builder gets updated properly in my Build method. Is there anything wrong I am doing.

Solution

The issue is that you are passing the Builder by value, so you are creating a copy of it. The method makes changes to the copy, so the calling method never sees the changes.

You could fix it by passing a pointer (*strings.Builder), but I wouldn’t pass the Builder into the second method at all. In my mind, it makes for more complicated and less reusable code. Unless this code is in some ultra-performance critical section of code the slight performance boost wouldn’t be worth it.

This is how I would code it:

func Build(queryMap map[string][]QueryFilter, clientId int64, template []string) string {
    var resourceBuilder strings.Builder
    for _, propertyName := range template {
        queryFilters := queryMap[propertyName]
        resourceBuilder.WriteString(GetResourceString(queryFilters))
    }
    fmt.Println("output: ", resourceBuilder.String())
    return resourceBuilder.String()
}


func GetResourceString(resourcesOpt []QueryFilter) string {
    var resourceBuilder strings.Builder
    for i, qf := range resourcesOpt {
        resourceBuilder.WriteString(qf.Resource.ResourceType)
        resourceBuilder.WriteString("-")
        resourceBuilder.WriteString(strconv.Itoa(qf.Resource.ResourceId))
        if i > 0 {
            resourceBuilder.WriteString("+")
        } 
    }
    return resourceBuilder.String()
}

Answered By – Toivo Lainevool

Answer Checked By – David Goodson (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.