Go에서 2D 슬라이스를 만드는 간결한 방법은 무엇입니까?
A Tour of Go를 통해 Go를 배우고 있습니다. 거기에있는 연습 중 하나 는를 포함하는 dy
행과 dx
열의 2D 슬라이스를 생성하도록 요청합니다 uint8
. 작동하는 현재 접근 방식은 다음과 같습니다.
a:= make([][]uint8, dy) // initialize a slice of dy slices
for i:=0;i<dy;i++ {
a[i] = make([]uint8, dx) // initialize a slice of dx unit8 in each of dy slices
}
나는 그것을 초기화하기 위해 각 슬라이스를 반복하는 것이 너무 장황하다고 생각합니다. 그리고 슬라이스에 더 많은 차원이 있으면 코드가 다루기 어려워집니다. Go에서 2D (또는 n 차원) 슬라이스를 초기화하는 간결한 방법이 있습니까?
더 간결한 방법은 없습니다. "올바른"방법을 사용했습니다. 슬라이스는 항상 1 차원이지만 더 높은 차원의 객체를 구성하도록 구성 될 수 있기 때문입니다. 자세한 내용은 다음 질문을 참조하십시오. Go : 2 차원 배열의 메모리 표현 방법 .
단순화 할 수있는 한 가지는 다음과 같은 for range
구성 을 사용하는 것입니다 .
a := make([][]uint8, dy)
for i := range a {
a[i] = make([]uint8, dx)
}
또한 컴포지트 리터럴로 슬라이스를 초기화 하면 "무료"를 얻을 수 있습니다. 예를 들면 다음과 같습니다.
a := [][]uint8{
{0, 1, 2, 3},
{4, 5, 6, 7},
}
fmt.Println(a) // Output is [[0 1 2 3] [4 5 6 7]]
예, 모든 요소를 열거해야하므로 한계가 있습니다. 그러나 몇 가지 트릭이 있습니다. 즉, 모든 값을 열거 할 필요가없고 슬라이스 요소 유형의 0 값 이 아닌 값만 열거 할 필요가 있습니다 . 이에 대한 자세한 내용은 golang 배열 초기화의 키 항목을 참조하세요 .
예를 들어, 당신은 처음 10 개 요소가 제로가 다음 다음 조각하려는 경우 1
와 2
이 같이 생성 할 수 있습니다 :
b := []uint{10: 1, 2}
fmt.Println(b) // Prints [0 0 0 0 0 0 0 0 0 0 1 2]
또한 slices 대신 배열 을 사용하면 매우 쉽게 만들 수 있습니다.
c := [5][5]uint8{}
fmt.Println(c)
출력은 다음과 같습니다.
[[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
배열의 경우 "외부"배열을 반복하고 "내부"배열을 초기화 할 필요가 없습니다. 배열은 설명자가 아니라 값이기 때문입니다. 자세한 내용은 블로그 게시물 배열, 슬라이스 (및 문자열) : '추가'메커니즘 을 참조하십시오.
Go Playground 에서 예제를 시도해보십시오 .
슬라이스를 사용하여 행렬을 만드는 방법에는 두 가지가 있습니다. 그들 사이의 차이점을 살펴 보겠습니다.
첫 번째 방법 :
matrix := make([][]int, n)
for i := 0; i < n; i++ {
matrix[i] = make([]int, m)
}
두 번째 방법 :
matrix := make([][]int, n)
rows := make([]int, n*m)
for i := 0; i < n; i++ {
matrix[i] = rows[i*m : (i+1)*m]
}
In regards to the first method, making successive make
calls doesn't ensure that you will end up with a contiguous matrix, so you may have the matrix divided in memory. Let's think of an example with two Go routines that could cause this:
- The routine #0 runs
make([][]int, n)
to get allocated memory formatrix
, getting a piece of memory from 0x000 to 0x07F. - Then, it starts the loop and does the first row
make([]int, m)
, getting from 0x080 to 0x0FF. - In the second iteration it gets preempted by the scheduler.
- The scheduler gives the processor to routine #1 and it starts running. This one also uses
make
(for its own purposes) and gets from 0x100 to 0x17F (right next to the first row of routine #0). - After a while, it gets preempted and routine #0 starts running again.
- It does the
make([]int, m)
corresponding to the second loop iteration and gets from 0x180 to 0x1FF for the second row. At this point, we already got two divided rows.
With the second method, the routine does make([]int, n*m)
to get all the matrix allocated in a single slice, ensuring contiguity. After that, a loop is needed to update the matrix pointers to the subslices corresponding to each row.
You can play with the code shown above in the Go Playground to see the difference in the memory assigned by using both methods. Note that I used runtime.Gosched()
only with the purpose of yielding the processor and forcing the scheduler to switch to another routine.
Which one to use? Imagine the worst case with the first method, i.e. each row is not next in memory to another row. Then, if your program iterates through the matrix elements (to read or write them), there will probably be more cache misses (hence higher latency) compared to the second method because of worse data locality. On the other hand, with the second method it may not be possible to get a single piece of memory allocated for the matrix, because of memory fragmentation (chunks spread all over the memory), even though theoretically there may be enough free memory for it.
Therefore, unless there's a lot of memory fragmentation and the matrix to be allocated is huge enough, you would always want to use the second method to get advantage of data locality.
You can refer this piece of code -
package main
import "fmt"
func main() {
var row, col int
fmt.Print("enter rows cols: ")
fmt.Scan(&row, &col)
// allocate composed 2d array
a := make([][]int, row)
for i := range a {
a[i] = make([]int, col)
}
// array elements initialized to 0
fmt.Println("a[0][0] =", a[0][0])
// assign
a[row-1][col-1] = 7
// retrieve
fmt.Printf("a[%d][%d] = %d\n", row-1, col-1, a[row-1][col-1])
// remove only reference
a = nil
// memory allocated earlier with make can now be garbage collected.
}
참고URL : https://stackoverflow.com/questions/39804861/what-is-a-concise-way-to-create-a-2d-slice-in-go
'Program Tip' 카테고리의 다른 글
PostgreSQL에서 누적 합계 계산 (0) | 2020.12.08 |
---|---|
dockerfile을 통해 docker 이미지를 빌드하는 동안 cmd 행을 통해 ENV 변수를 전달할 수 있습니까? (0) | 2020.12.08 |
문자열 상수와 문자열 리터럴의 차이점은 무엇입니까? (0) | 2020.12.08 |
Git에서 브랜치를 별칭으로 지정할 수 있습니까? (0) | 2020.12.08 |
C # 코드에서 (큰) XML을 구문 분석하는 가장 좋은 방법은 무엇입니까? (0) | 2020.12.08 |