Prosty unsafeCoerce
nie będzie działać, jak układ konstruktorów danych jest inna:
data StorableArray i e = StorableArray !i !i Int !(ForeignPtr e)
vs.
data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
{-# UNPACK #-} !Int -- offset
{-# UNPACK #-} !Int -- length
Można importować Data.Array.Storable.Internals
i Data.ByteString.Internal
aby uzyskać dostęp do surowych konstruktorów a następnie skonstruuj jedno z pozostałych bez kopiowania danych:
> let bs = pack [1,2,3]
> bs
"\SOH\STX\ETX"
> let sa = case bs of (PS ptr 0 n) -> StorableArray 0 (n-1) n ptr
> :t sa
sa :: StorableArray Int GHC.Word.Word8
> Data.Array.MArray.readArray sa 1
2
> Data.Array.MArray.readArray sa 0
1
> Data.Array.MArray.readArray sa 3
*** Exception: Ix{Int}.index: Index (3) out of range ((0,2))
(Usunąłem raczej długi znak zachęty Prelude Data.Array.Storable.Internals Data.ByteString.Internal Data.ByteString>
).
To nie zadziała dla Data.Vector.Unboxed
, ponieważ tutaj dane są na stercie Haskella i zarządzane przez środowisko wykonawcze GHC, podczas gdy pozostałe dwa zarządzają danymi poza stertą Haskella.
W niektórych przypadkach korzystne byłoby skopiować. Jeśli Twoje bytestrings są krótkimi segmentami dłuższego oryginalnego testu bytowego, np. ('BS.take 10 someLongByteString'), cała długa porcja zostanie zachowana przez' ForeignPtr'. W tym przypadku kopiowanie jest często lepsze, ponieważ zużywa znacznie mniej pamięci. Jest to rodzaj specjalistycznego przypadku, ale zdaje się często pojawiać. –