오늘은 단 하루지만 주말이에요. Go1.17에 관한 작은 소식을 전해드리겠습니다. 매일 물고기를 유인하는 스킬을 획득하세요!
Go 언어에서 슬라이스에는 배열이 독립 변수로 어딘가에 존재하는지 아니면 슬라이싱을 지원하기 위해 할당된 익명 배열인지에 관계없이 지원 배열에 대한 참조가 포함됩니다.
슬라이싱의 기본 구조는 다음과 같습니다.
// runtime/slice.go type slice struct { array unsafe.Pointer // 指向底层数组的指针 len int // 长度 cap int // 容量 }
슬라이싱이 배열을 지원하는 현재 방식은 슬라이싱 시 흥미로운 메모리 누수를 일으키거나 슬라이싱에 놀라운 변화를 가져올 수 있습니다.
또 다른 매우 중요한 점은 Go 1.16 이전에는 슬라이스 유형에서 배열 유형으로 변환하는 안전한 방법이 없다는 점입니다. 이는 매우 무력합니다.
표준 라이브러리를 Reflect 또는 unsafe로 호출하고 안전하지 않은 코드를 작성해야만 이 작업을 수행할 수 있습니다.
(*[10]byte)(unsafe.Pointer(&b[0]))
분명히 이것은 공식적으로 unsafe 사용을 권장하지 않습니다. 일단 처리가 잘못되면 치명적일 수 있습니다. 오류가 발생하고 상대적으로 통제가 불가능합니다.
사실 Go가 출시된 직후(Go 1.0이 출시되기 오래 전)인 2009년 초에 일부 사람들은 관련 의구심을 제기하고 이 문제를 해결하기를 희망했습니다.
마지막으로 다가오는 Go 1.17에서는 이 커밋 ID #1c268431f4로 시작하는 일련의 변경으로 인해 가능해졌습니다. 업데이트된 사양:
새 사양에서 이에 대한 설명은 간단합니다.
슬라이스를 배열 포인터로 변환 슬라이스의 기본 배열에 대한 포인터를 생성합니다. 슬라이스의 길이가 배열의 길이보다 작으면 런타임 패닉이 발생합니다.
- 슬라이스의 길이가 배열의 길이보다 길면 배열은 무해하며 정상적인 작동이 가능합니다.
- 슬라이스가 어레이보다 길면 어레이가 원래 슬라이스의 모든 지원 어레이에 액세스할 수 없음을 의미합니다.
또한 사양은 Go1.17에서 사용할 수 있는 몇 가지 새로운 예를 제공합니다.
s := make([]byte, 2, 4) s0 := (*[0]byte)(s) // s0 != nil s2 := (*[2]byte)(s) // &s2[0] == &s[0] s4 := (*[4]byte)(s) // panics: len([4]byte) > len(s) var t []string t0 := (*[0]string)(t) // t0 == nil t1 := (*[1]string)(t) // panics: len([1]string) > len(s)
- 변수 s2의 변환: 슬라이스의 기본 배열을 변환합니다. 이 변환은 a를 할당하지 않습니다. 새로운 어레이로 효율성을 보장합니다.
- 변수 s0 및 t0의 변환: 비어 있지 않은 조각을 길이가 0인 배열로 변환합니다. 길이가 0인 배열로는 아무 것도 할 수 없지만 여전히 nil인 유효한 포인터를 제공해야 합니다.
현재 유형 어설션과 같은 범위를 벗어난 이유로 인해 패닉 이벤트가 발생하는지 확인할 방법이 없다는 점에 유의해야 합니다. 너무 짧은 스니펫이 있어 패닉 이벤트를 일으킬 수 있다고 생각되면 사전 결정을 사용해야 합니다.
동시에 Reflect를 사용하여 관련 변환 작업을 수행하는 경우 표준 라이브러리 Reflect도 업데이트되어 슬라이스에서 배열 포인터로의 변환을 지원합니다.
Go 언어의 유형 변환에 대해 다른 생각과 요구가 있거나 함정에 직면하셨나요?
누구나 댓글 영역에 메시지를 남기고 소통할 수 있습니다.