I’m using Go 1.22+ weak pointers to implement a read-only iterator that holds a weak reference to a file system. The issue is that my file system is stored as an interface field, and that interface embeds another interface.
The Problem:
I have:
type FileStorageGargoyle struct {
mu sync.RWMutex
fs gargoyle.FileSystem // interface type
}
type FileStorageGargoyleReadFileIterator struct {
fs weak.Pointer[gargoyle.Snapshot] // want weak ptr to embedded interface
}
func (s *FileStorageGargoyle) ReadFile(fileId string (io.ReadSeekCloser, error) {
s.mu.RLock()
defer s.mu.RUnlock()
// This doesn't work - type mismatch:
// fs: weak.Make(&s.fs), // s.fs is FileSystem, not Snapshot
}
Where gargoyle.FileSystem embeds gargoyle.Snapshot:
type FileSystem interface {
Snapshot // embedded
CreateFile(id string) error
// ... other methods
}
What I Tried:
-
Direct assignment: weak.Make(&s.fs) — compilation error, type mismatch
-
Type assertion: weak.Make(&(s.fs.(gargoyle.Snapshot))) — creates a local variable, weak pointer becomes dangling
-
Variable copy:
var fs gargoyle.Snapshot = s.fs
weak.Make(&fs) // Also dangling - fs is on the stack
The Workaround (Works, but feels awkward):
import "unsafe"
fs: weak.Make((*gargoyle.Snapshot)(unsafe.Pointer(&s.fs))),
This works because FileSystem embeds Snapshot, so the memory layout is compatible. The unsafe.Pointer cast lets me point directly to the s.fs field in the struct, which persists for the object’s lifetime.
My Questions:
- Is this the intended way to handle weak pointers to embedded interface fields?
- Are there safer alternatives that don’t involve unsafe?
- Should the weak package documentation cover this use case?
- Is there a Go idiom I’m missing here?
- I’d appreciate any feedback or suggestions!