我有一个看起来像这样的结构:
pub struct MyStruct {
data: Arc<Mutex<HashMap<i32, Vec<i32>>>>,
}
Run Code Online (Sandbox Code Playgroud)
我可以很容易地锁定互斥锁并查询底层HashMap:
let d = s.data.lock().unwrap();
let v = d.get(&1).unwrap();
println!("{:?}", v);
Run Code Online (Sandbox Code Playgroud)
现在我想创建一个封装查询的方法,所以我写了这样的东西:
impl MyStruct {
pub fn get_data_for(&self, i: &i32) -> &Vec<i32> {
let d = self.data.lock().unwrap();
d.get(i).unwrap()
}
}
Run Code Online (Sandbox Code Playgroud)
这无法编译,因为我试图在以下情况下返回对数据的引用Mutex:
error: `d` does not live long enough
--> <anon>:30:9
|
30 | d.get(i).unwrap()
| ^
|
note: reference must be valid for the anonymous lifetime #1 defined on the block at 28:53...
--> <anon>:28:54
|
28 …Run Code Online (Sandbox Code Playgroud) 是否可以编写一个类型级函数,True如果一个类型级别列表包含另一个类型级别列表,则返回该函数?
这是我的尝试:
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module TypePlayground where
import Data.Type.Bool
type family InList (x :: *) (xs :: [*]) where
InList x '[] = 'False
InList x (x ': xs) = 'True
InList x (a ': xs) = InList x xs
type family ListContainsList (xs :: [*]) (ys :: [*]) where
ListContainsList xs (y ': ys) = InList y xs && ListContainsList xs ys
ListContainsList …Run Code Online (Sandbox Code Playgroud) 假设我有这种数据类型:
data SomeDataType a = SomeDataType a
Run Code Online (Sandbox Code Playgroud)
我想向用户显示它的表示(在控制台输出中),所以我需要一个“漂亮的打印”功能。我不想使用show,因为它会返回一个表达式,而我只想将我的类型的唯一字段的值转换为字符串。
我希望这种行为:
>>> let myintdata = SomeDataType (22::Int)
>>> putStrLn $ prettyPrint myintdata
22
>>> let alice = SomeDataType "Alice"
>>> let bob = SomeDataType "Bob"
>>> putStrLn $ prettyPrint alice ++ " loves " ++ prettyPrint bob
Alice loves Bob
Run Code Online (Sandbox Code Playgroud)
所以我是这样实现的:
prettyPrint :: Show a => SomeDataType a -> String
prettyPrint (SomeDataType x) = show x
Run Code Online (Sandbox Code Playgroud)
它适用于数字,但字符串被引用和转义:
>>> let alice = SomeDataType "Alice"
>>> let bob = SomeDataType "Bob"
>>> …Run Code Online (Sandbox Code Playgroud) 在我的简短Rust经历中,我多次遇到这种模式,我不确定我解决它的方式是否足够......
让我们假设我有一些看起来像这样的特征:
trait Container {
type Item;
fn describe_container() -> String;
}
Run Code Online (Sandbox Code Playgroud)
还有一些实现这个特性的结构:
struct ImAContainerType;
struct ImAnItemType;
impl Container for ImAContainerType {
type Item = ImAnItemType;
fn describe_container() -> String { "some container that contains items".to_string() }
}
Run Code Online (Sandbox Code Playgroud)
这可能是一个容器,它知道它包含的项目类型,如本例所示,或者,作为另一个例子,知道应该返回什么类型的响应的请求等.
现在我发现自己处于某种情况,当我需要实现一个带有项(相关类型)的函数并调用容器的静态函数(父特征)时.这是第一次天真的尝试:
fn describe_item_container<C: Container>(item: C::Item) -> String {
C::describe_container()
}
Run Code Online (Sandbox Code Playgroud)
这不会编译,因为关联类型不是单射的,并且Item可能有几个可能的Containers,所以这整个情况是模糊的.我需要以某种方式提供实际Container类型,但不提供任何容器数据.当我调用这个函数时,我可能根本没有容器数据本身!
在寻找解决方案时,我找到了std :: marker :: PhantomData的文档.它说:
PhantomData允许您描述类型的行为就像存储类型T的值一样,即使它没有.
这必须是Rust替代Haskell的Proxy类型,对吧?我们试着用它:
fn describe_item_container<C: Container>(container: PhantomData<C>, item: C::Item) -> String {
C::describe_container()
}
let s …Run Code Online (Sandbox Code Playgroud) 对于这些数据:
data A = A
data B = B
class C1 a where repr :: a -> String
instance C1 A where repr _ = "A"
instance C1 B where repr _ = "B"
class C2 a
instance C2 A
Run Code Online (Sandbox Code Playgroud)
有没有办法用这种类型实现功能?
conv :: (C1 a, C2 b) => a -> Maybe b
Run Code Online (Sandbox Code Playgroud)
它应返回Just . id作为实例的类型的参数C2,以及Nothing任何其他类型的参数.
repr是单射的.我可以更改类C2但是类C1在外部库中.
对于任何特定类型A:
data A = A Int
Run Code Online (Sandbox Code Playgroud)
有可能写这个功能吗?
filterByType :: a -> Maybe a
Run Code Online (Sandbox Code Playgroud)
Just . id如果A给出了type的值,并且Nothing对于任何其他类型的值,它应该返回.
使用任何手段(GHC exts,TH,introspection等)
NB.由于我关于Haskell类型系统的最后一个问题被社区批评为"非常过分简化",我觉得有必要说明,这是对Haskell类型系统限制的纯粹学术兴趣,没有任何特定的任务需要解决.