如何以一种惯用的方式预分配和填充一些指针?

时间:2013-06-03 21:26:34

标签: go slice

http://play.golang.org/p/j-Y0mQzTdP

package main

import "fmt"

type UselessStruct struct {
    a int
    b int
}

func main() {
    mySlice := make([]*UselessStruct, 5)
    for i := 0; i != 5; i++ {
        mySlice = append(mySlice, &UselessStruct{})
    }

    fmt.Println(mySlice)
}

输出:[<nil> <nil> <nil> <nil> <nil> 0xc010035160 0xc010035170 0xc010035180 0xc010035190 0xc0100351a0]

我想做的是为5个UselessStructs预分配内存,存储为指针。如果我声明一片结构值eq:

mySlice := make([]UselessStruct, 5)

然后这会创建5个空结构 - 附加不会替换空结构,而是继续添加到切片,所以这个代码的最终结果是:

http://play.golang.org/p/zBYqGVO85h

package main

import "fmt"

type UselessStruct struct {
    a int
    b int
}

func main() {
    mySlice := make([]UselessStruct, 5)
    for i := 0; i != 5; i++ {
        mySlice = append(mySlice, UselessStruct{})
    }

    fmt.Println(mySlice)
}

是:[{0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0}]

预分配和填充切片的惯用方法是什么?

4 个答案:

答案 0 :(得分:28)

对于你的第一个例子,我会这样做:

mySlice := make([]*UselessStruct, 5)
for i := range mySlice {
     mySlice[i] = new(UselessStruct)
}

您在两个示例中遇到的问题是您要附加到已经是正确长度的切片。如果设置mySlice := make([]*UselessStruct, 5),则需要一段长度为5的nil指针。如果附加一个指针,它现在的长度为6。

相反,您要使用mySlice := make([]*UselessStruct, 0, 5)。这会创建一个长度为0但容量为5的切片。每次附加它都会在长度上添加一个,但在超过切片容量之前不会重新分配。

mySlice := make([]*UselessStruct, 0, 5)
for i := 0; i != 5; i++ {
    mySlice = append(mySlice, &UselessStruct{})
}
// mySlice is [0xc010035160 0xc010035170 0xc010035180 0xc010035190 0xc0100351a0]

我的两个例子都会按照您的预期运作,但出于纯粹的风格原因,我推荐第一个例子。

答案 1 :(得分:8)

有两种方法可以做到这一点。一种方法是像你一样预先分配插槽。 但是,您只需索引到其中一个现有广告位,而不是使用append

mySlice[i] = &UselessStruct{}

第二种是使用make的'重载'版本。您指定零长度,但容量为5。

package main

type T struct {
    A int
    B int
}

func main() {
    mySlice := make([]*T, 0, 5)
    for i := 0; i < 5; i++ {
        mySlice = append(mySlice, &T{1, 2})
    }
}

mySlice := make([]*T, 0, 5)初始化切片的长度为零,但它仍然为5个条目预先分配了足够的空间。

答案 2 :(得分:3)

你确定需要指针吗?您的结构具有零值,因此:

mySlice := make([]UselessStruct, 5) # has memory preallocated for 5 UselessStructs.

由于切片是引用类型,因此您实际上有5个指向这5个UselessStructs的指针。

如果您需要获取对单个结构的引用,那么您可以这样

myStruct := &mySlice[0]

现在你有一个指向UseLessStruct的指针,你可以根据需要使用它。它的代码远远少于你的代码,并利用了Go的零值功能。

答案 3 :(得分:0)

刚刚完成:追加与nil切片一起工作,所以你不需要用make创建切片,你可以只添加元素。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="user"
            type="com.example.ViewUser" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

                <EditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="top"
                    android:lines="3"
                    android:text="@{user.name}" />
    </LinearLayout>
</layout>

这与前面的示例相同,没有预先分配,但如果你知道大小,你宁愿使用类似这样的东西:

var mySlice []*UselessStruct
for i := 0; i < 5; i++ {
    mySlice = append(mySlice, &UselessStruct{})
}

这可以避免一些重新分配。

相关问题