Конкатентные фрагменты в голанге

Я пытаюсь объединить несколько фрагментов следующим образом,

package routes

import (
    "net/http"
)

type Route struct {
    Name        string
    Method      string
    Pattern     string
    Secured     bool
    HandlerFunc http.HandlerFunc
}

type Routes []Route

var ApplicationRoutes Routes

func init() {
    ApplicationRoutes = append(
        WifiUserRoutes,
        WifiUsageRoutes,
        WifiLocationRoutes,
        DashboardUserRoutes,
        DashoardAppRoutes,
        RadiusRoutes,
        AuthenticationRoutes...
    )
}

Однако встроенный append() способен добавлять два среза, поэтому он выдает слишком много аргументов для добавления во время компиляции. Есть ли альтернативная функция для достижения этой задачи? или есть лучший способ объединить срезы?

Ответ 1

append работает с отдельными элементами, а не с целыми фрагментами. Добавить каждый срез в цикле

routes := []Routes{
    WifiUserRoutes,
    WifiUsageRoutes,
    WifiLocationRoutes,
    DashboardUserRoutes,
    DashoardAppRoutes,
    RadiusRoutes,
    AuthenticationRoutes,
}

var ApplicationRoutes []Route
for _, r := range routes {
    ApplicationRoutes = append(ApplicationRoutes, r...)
}

Ответ 2

Этот вопрос уже был дан, но я хотел опубликовать его здесь, потому что принятый ответ не самый эффективный.

Причина в том, что создание пустого фрагмента, а затем добавление может привести к множеству ненужных распределений.

Наиболее эффективным способом было бы предварительно выделить срез и скопировать в него элементы. Ниже представлен пакет, который реализует конкатенацию в обоих направлениях. Если вы проводите тестирование, вы увидите, что предварительное выделение ~ 2x быстрее и выделяет гораздо меньше памяти.

Результаты тестов:

go test . -bench=. -benchmem
testing: warning: no tests to run
BenchmarkConcatCopyPreAllocate-8    30000000            47.9 ns/op        64 B/op          1 allocs/op
BenchmarkConcatAppend-8             20000000           107 ns/op         112 B/op          3 allocs/op

Пакет concat:

package concat

func concatCopyPreAllocate(slices [][]byte) []byte {
    var totalLen int
    for _, s := range slices {
        totalLen += len(s)
    }
    tmp := make([]byte, totalLen)
    var i int
    for _, s := range slices {
        i += copy(tmp[i:], s)
    }
    return tmp
}

func concatAppend(slices [][]byte) []byte {
    var tmp []byte
    for _, s := range slices {
        tmp = append(tmp, s...)
    }
    return tmp
}

Тесты тестов:

package concat

import "testing"

var slices = [][]byte{
    []byte("my first slice"),
    []byte("second slice"),
    []byte("third slice"),
    []byte("fourth slice"),
    []byte("fifth slice"),
}

var B []byte

func BenchmarkConcatCopyPreAllocate(b *testing.B) {
    for n := 0; n < b.N; n++ {
        B = concatCopyPreAllocate(slices)
    }
}

func BenchmarkConcatAppend(b *testing.B) {
    for n := 0; n < b.N; n++ {
        B = concatAppend(slices)
    }
}