在使用for循环追加切片时出现了意外的结果。

huangapple go评论106阅读模式
英文:

appending to a slice in for loop with unexpected results

问题

这可能是一个愚蠢的问题,但是当我尝试将一个[]byte切片追加到一个[][]byte切片时,我得到了奇怪的结果。

这是我的代码:

func Normalizer(s string) (ss [][]byte) {
    ss = make([][]byte, 0)
    // norm
    var ia norm.Iter
    ia.InitString(norm.NFC, s)

    for !ia.Done() {
        next := ia.Next()
        fmt.Println(next)
        // [226 128 139]
        // [227 128 129]
        // [39]
        // [226 128 153]
        // [46]
        // [44]
        // [63]
        // [33]
        // [92]
        // [10]
        // [226 128 153]
        // ...
        ss = append(ss, next)
    }
    ia.Done()

    fmt.Println(ss)
    return
}

我期望得到这样的结果:

// [[226 128 139] [227 128 129] [39] [226 128 153] [46] [44] [63] [33] [92] [10] [226 128 153]...]

但是实际上我得到了这样的结果:

// [[226 129 128] [226 129 128] [226] [226 129 128] [226] [226] [226] [226] [226] [226] [226 129 128]...]

我不知道为什么会这样。希望能得到帮助和解释。

英文:

It could be a silly question but when I try to append a []byte slice to a [][]byte slice I get weird results.

Here is my code:

func Normalizer(s string) (ss [][]byte) {

    ss = make([][]byte, 0)
    // norm
    var ia norm.Iter

    ia.InitString(norm.NFC, s)

    for !ia.Done() {

	    next := ia.Next()

	    fmt.Println(next)
	    // [226 128 139]
	    // [227 128 129]
	    // [39]
	    // [226 128 153]
	    // [46]
	    // [44]
	    // [63]
	    // [33]
	    // [92]
	    // [10]
	    // [226 128 153]
        // ...
	    ss = append(ss, next)

    }
    ia.Done()


    fmt.Println(ss)
    return
}

I'm expecting somethin like this:

// [[226 128 139] [227 128 129] [39] [226 128 153] [46] [44] [63] [33] [92] [10] [226 128 153]...] 

but instead i get this:

// [[226 129 128] [226 129 128] [226] [226 129 128] [226] [226] [226] [226] [226] [226] [226 129 128]...]

and I have no idea why. Help and explanation would be appreciated.

答案1

得分: 3

切片是一个结构体,包含指向底层数组的指针、长度和容量。

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

在追加切片结构之后,你正在更改底层数组。ia.Next() 重用其返回缓冲区。

例如,

package main

import (
    "fmt"

    "golang.org/x/text/unicode/norm"
)

func Normalizer(s string) (ss [][]byte) {
    ss = make([][]byte, 0)
    var ia norm.Iter
    ia.InitString(norm.NFC, s)
    for !ia.Done() {
        next := ia.Next()
        fmt.Println(string(next), &next[0])
        ss = append(ss, next)
    }
    fmt.Println()
    for i := range ss {
        fmt.Println(string(ss[i]), &ss[i][0])
    }
    fmt.Println()
    return
}

func main() {
    ss := Normalizer("abc")
    fmt.Printf("%s\n", ss)
}

输出:

a 0xc420092228
b 0xc420092228
c 0xc420092228

c 0xc420092228
c 0xc420092228
c 0xc420092228

[c c c]

将切片结构的副本替换为具有新底层数组的新切片结构:

next := append([]byte(nil), ia.Next()...)

例如,

package main

import (
    "fmt"

    "golang.org/x/text/unicode/norm"
)

func Normalizer(s string) (ss [][]byte) {
    ss = make([][]byte, 0)
    var ia norm.Iter
    ia.InitString(norm.NFC, s)
    for !ia.Done() {
        next := append([]byte(nil), ia.Next()...)
        fmt.Println(string(next), &next[0])
        ss = append(ss, next)
    }
    fmt.Println()
    for i := range ss {
        fmt.Println(string(ss[i]), &ss[i][0])
    }
    fmt.Println()
    return
}

func main() {
    ss := Normalizer("abc")
    fmt.Printf("%s\n", ss)
}

输出:

a 0xc4200120d0
b 0xc4200120e8
c 0xc420012108

a 0xc4200120d0
b 0xc4200120e8
c 0xc420012108

[a b c]

参考资料:

Slice types

Go Slices: usage and internals

Arrays, slices (and strings): The mechanics of 'append'

英文:

A slice is a struct with a pointer to an underlying array, a length, and a capacity.

type slice struct {
	array unsafe.Pointer
	len   int
	cap   int
}

You are changing the underlying array after you have appended the slice struct. ia.Next() reuses its return buffer.

For example,

package main

import (
	"fmt"

	"golang.org/x/text/unicode/norm"
)

func Normalizer(s string) (ss [][]byte) {
	ss = make([][]byte, 0)
	var ia norm.Iter
	ia.InitString(norm.NFC, s)
	for !ia.Done() {
		next := ia.Next()
		fmt.Println(string(next), &next[0])
		ss = append(ss, next)
	}
	fmt.Println()
	for i := range ss {
		fmt.Println(string(ss[i]), &ss[i][0])
	}
	fmt.Println()
	return
}

func main() {
	ss := Normalizer("abc")
	fmt.Printf("%s\n", ss)
}

Output:

a 0xc420092228
b 0xc420092228
c 0xc420092228

c 0xc420092228
c 0xc420092228
c 0xc420092228

[c c c]

Replace a copy of a slice struct

next := ia.Next()

with a new slice struct with a new underlying array

next := append([]byte(nil), ia.Next()...)

For example,

package main

import (
	"fmt"

	"golang.org/x/text/unicode/norm"
)

func Normalizer(s string) (ss [][]byte) {
	ss = make([][]byte, 0)
	var ia norm.Iter
	ia.InitString(norm.NFC, s)
	for !ia.Done() {
		next := append([]byte(nil), ia.Next()...)
		fmt.Println(string(next), &next[0])
		ss = append(ss, next)
	}
	fmt.Println()
	for i := range ss {
		fmt.Println(string(ss[i]), &ss[i][0])
	}
	fmt.Println()
	return
}

func main() {
	ss := Normalizer("abc")
	fmt.Printf("%s\n", ss)
}

Output:

a 0xc4200120d0
b 0xc4200120e8
c 0xc420012108

a 0xc4200120d0
b 0xc4200120e8
c 0xc420012108

[a b c]

References:

Slice types

Go Slices: usage and internals

Arrays, slices (and strings): The mechanics of 'append'

huangapple
  • 本文由 发表于 2017年8月22日 00:27:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/45801809.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定