In Go 1.21 we are introducing some new functions in the unsafe package: unsafe.Slice
, unsafe.SliceData
, unsafe.String
, unsafe.StringData
. It should be possible to access this functionality through the reflect package as well.
The value returned by unsafe.SliceData
is already available by calling the reflect.Value.Pointer
method.
I propose that we extend reflect.Value.Pointer
so that if it is called on a value of kind String
, it returns the equivalent of unsafe.StringData
.
The equivalent to unsafe.String
is simply reflect.ValueOf(unsafe.String((*byte)(vp.UnsafePointer()), n))
, so I don't think we need to add anything for that.
I propose one new function:
package reflect
// UnsafeSlice returns a Value representing a slice whose underlying data starts at vp,
// with length and capacity equal to n. vp.Kind() must be Pointer.
// The returned slice will have element type vp.Type().Elem().
// This is like unsafe.Slice.
func UnsafeSlice(vp Value, n int) Value
(edited to change function name from Slice
to UnsafeSlice`)
Comment From: bcmills
It seems to me that the new functionality is to MakeSlice
as NewAt
is to New
. So I suggest:
func SliceAt(typ Type, p unsafe.Pointer, len int) Value
That has the additional advantage of passing through the type unsafe.Pointer
, which clarifies that it is in fact unsafe.
Comment From: rittneje
Why does the proposed reflect.Slice
(or reflect.SliceAt
) require the length and capacity to be the same instead of having two separate parameters like reflect.MakeSlice
?
Comment From: DeedleFake
Those functions were introduced starting in 1.17 and then more in 1.20.
The equivalent to
unsafe.String
is simplyreflect.ValueOf(unsafe.String(vp.Pointer(), n))
, so I don't think we need to add anything for that.
That won't work. unsafe.String()
requires a *byte
, not a uintptr
. The conversion requires first converting through an unsafe.Pointer
, so I think having an equivalent top-level function makes sense for that one, too. It's not really any different from a slice otherwise except for the type always being the same:
reflect.ValueOf(unsafe.String((*byte)(unsafe.Pointer(v.Pointer())), v.Len()))
reflect.ValueOf(unsafe.Slice((*T)(unsafe.Pointer(v.Pointer())), v.Len()))
Comment From: bcmills
Why does the proposed
reflect.Slice
(orreflect.SliceAt
) require the length and capacity to be the same … ?
Because unsafe.Slice
does too. Most of the time you do want them to be the same, and if you want to reduce the capacity that's easy enough to do as a separate operation (via SetCap
).
Comment From: bcmills
For the string case,
reflect.ValueOf(unsafe.String(v.Interface().(*byte), v.Len()))
or
reflect.ValueOf(unsafe.String((*byte)(v.UnsafePointer()), v.Len()))
will often suffice.
Comment From: cuonglm
I think the function name should be UnsafeSlice
instead of Slice
.
Slice
is already taken as a Kind
.
Comment From: gopherbot
Change https://go.dev/cl/516597 mentions this issue: reflect: add UnsafeSlice
Comment From: gopherbot
Change https://go.dev/cl/516596 mentions this issue: reflect: handle String kind in Value.Pointer
Comment From: rsc
I think the function name should be UnsafeSlice instead of Slice. Slice is already taken as a Kind.
Another reason is that these are in fact unsafe, so the name should begin with Unsafe to distinguish it from the normal, safe reflect API.
Comment From: rsc
It seems like we should also update UnsafePointer to handle String (not just update Pointer).
Comment From: rsc
This proposal has been added to the active column of the proposals project and will now be reviewed at the weekly proposal review meetings. — rsc for the proposal review group
Comment From: rsc
Have all remaining concerns about this proposal been addressed?
Two parts to the proposal.
First, add func UnsafeSlice, mimicking unsafe.Slice.
Second, update Value.Pointer and Value.UnsafePointer to handle String.
Comment From: bcmills
I don't think the signature concern in https://github.com/golang/go/issues/61308#issuecomment-1631737298 has been addressed yet.
The other functions and methods in the reflect
package that use the word Unsafe
still explicitly require the use of the unsafe
package, but
func Slice(vp Value, n int) Value
(as described in https://github.com/golang/go/issues/61308#issue-1799861635) does not have that property.
Comment From: ianlancetaylor
I'm not sure that's quite true of the existing reflect.Value.UnsafePointer
method, which does return a value of type unsafe.Pointer
but can be used without importing the unsafe package.
Note that the proposed function is now named UnsafeSlice
rather than Slice
.
Comment From: aclements
I also prefer @bcmills ' alternate signature. It has the clear advantage of using unsafe.Pointer
, and I suspect in practice it will be more common that callers will have an unsafe.Pointer
already, rather than a Value
, so it will save the conversion (though they can convert either way).
Comment From: rsc
Have all remaining concerns about this proposal been addressed?
Two parts to the proposal.
First, add func SliceAt, analogous to NewAt (which probably should have been called ValueAt) but for slices:
func SliceAt(typ Type, p unsafe.Pointer, len int) Value
Second, update Value.Pointer and Value.UnsafePointer to handle String.
Comment From: rsc
Based on the discussion above, this proposal seems like a likely accept. — rsc for the proposal review group
Two parts to the proposal.
First, add func SliceAt, analogous to NewAt (which probably should have been called ValueAt) but for slices:
func SliceAt(typ Type, p unsafe.Pointer, len int) Value
Second, update Value.Pointer and Value.UnsafePointer to handle String.
Comment From: gopherbot
Change https://go.dev/cl/572117 mentions this issue: reflect: Value.Pointer and Value.UnsafePointer handle String
Comment From: gopherbot
Change https://go.dev/cl/572118 mentions this issue: reflect: add SliceAt
Comment From: cuonglm
Does reflect.SliceAt
do all the runtime validations that unsafe.Slice
do? For example, should this code panic?
_ = SliceAt(TypeOf(0), unsafe.Pointer((*int)(nil)), 1)
Comment From: rsc
Yes, reflect.SliceAt should be no more unsafe than unsafe.Slice. So it should do the same validations.
Comment From: rsc
No change in consensus, so accepted. 🎉 This issue now tracks the work of implementing the proposal. — rsc for the proposal review group
Two parts to the proposal.
First, add func SliceAt, analogous to NewAt (which probably should have been called ValueAt) but for slices:
func SliceAt(typ Type, p unsafe.Pointer, len int) Value
Second, update Value.Pointer and Value.UnsafePointer to handle String.
Comment From: gopherbot
Change https://go.dev/cl/575956 mentions this issue: reflect: add missing String case in Value.UnsafePointer doc
Comment From: gopherbot
Change https://go.dev/cl/592197 mentions this issue: doc/next: improve description of proposal 61308