有' S
newCString :: String -> IO CString
peekCString :: CString -> IO String
你需要
fromString :: String -> a
show :: a -> String
我的跛脚尝试
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverlappingInstances #-}
module Main where
import Data.String
import Foreign.C.String
import System.IO.Unsafe
instance IsString CString where
fromString = unsafePerformIO . newCString
instance {-# OVERLAPS #-} Show CString where
show = unsafePerformIO . peekCString
mycs :: CString
mycs = "hello CString"
main = putStrLn $ show mycs
似乎有效。但是,在我想知道我在这里设置了什么样的灾难之前从未说过unsafePerformIO
?我漏了记忆吗?有这种方便的安全方法吗?
答案 0 :(得分:8)
没有。例如,您的show
函数会在不同时间为相同的CString
值返回不同的结果。这是因为CString
实际上是一个可变字符串,相当于IORef String
。因为当评估表达式并且Haskell语言未指定表达式的计算次数时,使用您的实例的表达式show cs
将具有非确定性值,因此大多数 Haskell程序员会说这不是unsafePerformIO
的有效用法,并且(有意)不使用Show CString
来实现unsafePerformIO
。
答案 1 :(得分:6)
这可能在技术上是安全的,因为您永远不会更改CString
值指向的内存。因此,这些值确实是不可变的,unsafePerformIO
的效果只是模仿一个纯值。
然而,以上只是因为你永远不会释放内存,而只是在每次用newCString
分配新字符串时泄漏它。
只要使用free
修复内存泄漏,就会失去安全性:unsafePerformIO
将读取旧内存地址中找到的内容。如果运气好的话,这会导致程序崩溃。如果你运气不好,这会将垃圾数据读入你的字符串。祝你好好调试。
我强烈建议不要这样做。
TL; DR:
unsafePerformIO
不安全,除非您知道自己在做什么,否则不要使用它。 CString
,并且只能与外语交互。