小编Pie*_*ine的帖子

为什么函数体在结构中编译,而不是在特征中编译?

此代码定义了一个非常简单的特征,用于表示二叉树和实现该特征的结构:

pub trait BTree<T> {
    fn all(&self) -> Option<(&Self, &Self, &T)>;
    fn left(&self) -> Option<&Self>;
    fn right(&self) -> Option<&Self>;
    fn value(&self) -> Option<&T>;
}

pub struct MyBTree<T> {
    opt: Option<Box<(MyBTree<T>, MyBTree<T>, T)>>,
}

impl<T> BTree<T> for MyBTree<T> {
    fn all(&self) -> Option<(&Self, &Self, &T)> {
        match self.opt {
            None => None,
            Some(ref tuple) => Some((&tuple.0, &tuple.1, &tuple.2)),
        }
    }

    fn left(&self) -> Option<&Self> {
        match self.all() {
            None => None,
            Some((left, _, _)) => Some(left),
        }
    }

    fn right(&self) -> …
Run Code Online (Sandbox Code Playgroud)

traits rust

11
推荐指数
1
解决办法
188
查看次数

我可以强制一个特征是协变的吗?

感谢 @francis-gagn\xc3\xa9 \对另一个问题的出色回答,我对方差的工作原理有了更清晰的了解。例如,包含引用的类型在其生命周期参数上是协变的,如下所示。

\n\n
struct Foo<\'a> (PhantomData<&\'a str>);\n\n/// Foo is covariant over its lifetime parameter\npub fn test_foo<\'a:\'b, \'b:\'c, \'c>() {\n    let fa: Foo<\'a> = Foo(PhantomData);\n    let fb: Foo<\'b> = Foo(PhantomData);\n    let fc: Foo<\'c> = Foo(PhantomData);\n\n    let v: Vec<Foo<\'b>> = vec![fa, fb]; // fc is not accepted\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

另一方面,接受引用(或包含引用的类型)的函数在其生命周期参数上是逆变的。

\n\n
struct Bar<\'a> (PhantomData<fn(&\'a str)>);\n\n/// Bar is contravariant over its lifetime parameter\npub fn test_bar<\'a:\'b, \'b:\'c, \'c>() {\n    let ba: Bar<\'a> = Bar(PhantomData);\n    let bb: Bar<\'b> = Bar(PhantomData);\n    let bc: Bar<\'c> …
Run Code Online (Sandbox Code Playgroud)

covariance traits rust

6
推荐指数
2
解决办法
841
查看次数

合并两种错误类型的最惯用的方法是什么?

我有一个类型,Foo它的方法可能会“引发”相关类型的错误Foo::Err

pub trait Foo {
    type Err;
    
    fn foo(&mut self) -> Result<(), Self::Err>;
}
Run Code Online (Sandbox Code Playgroud)

我有另一个特性,它Bar有一个方法来处理Foo. Bar可能会发出自己的错误(由关联类型指定Bar::Err),但也可能会遇到由Foo它正在处理的生成的错误。

我可以看到两种方法来做到这一点,但我不知道哪一种最适合 Rust。

第一个将结果嵌入到结果中:

pub trait Bar1 {
    type Err;
    
    fn bar<F: Foo>(&mut self, foo: F) -> Result<Result<F, F::Err>, Self::Err>;
}
Run Code Online (Sandbox Code Playgroud)

第二个将两种错误类型合并到一个专用的枚举中:

pub trait Bar2 {
    type Err;
    
    fn bar<F: Foo>(&mut self, foo: F) -> Result<F, Choice<F::Err, Self::Err>>;
}
Run Code Online (Sandbox Code Playgroud)

第二个在语义上看起来更清晰,但为处理额外的枚举创建了一些障碍。

操场

error-handling idioms rust

5
推荐指数
2
解决办法
2441
查看次数

为何编译器以不同的方式对待这两条等效(?)行?

据我了解,x实现trait时Foo,以下两行应等效。

x.foo();
Foo::foo(&x);
Run Code Online (Sandbox Code Playgroud)

但是,我遇到的问题是编译器接受第一个,而拒绝第二个,并带有一个非常奇怪的错误消息。

与往常一样,此示例可在操场上找到

考虑以下两个相关特征。

pub trait Bar<'a> {
    type BarError: Into<MyError>;
    fn bar(&self) -> Result<(), Self::BarError>;
}

pub trait Foo: for<'a> Bar<'a> {
    type FooError: Into<MyError>;
    fn foo(&self) -> Result<(), Self::FooError>
    where
        for<'a> <Self as Bar<'a>>::BarError: Into<<Self as Foo>::FooError>;
}
Run Code Online (Sandbox Code Playgroud)

这个示例有点复杂,但是我确实需要使用生命周期参数Bar,而我不能使用它Foo。作为结果:

  • 我必须求助于高阶特质界限(HRTB);
  • 我不能依靠Bar::BarErrorFoo(实际上有类型无限多Bar<'_>::BarError),所以Foo必须有自己的FooError;
  • 所以我需要foo方法中绑定的复杂特征将BarErrors 转换为FooErrors。

现在,让我们来实现Bar,并Foo为具体的类型,例如 …

rust

5
推荐指数
1
解决办法
124
查看次数

为什么 `std::ptr::null` 不能用于未定义大小的类型?

据我了解,在 Rust 中创建空指针的标准(仅?)方法是std::ptr::null.

但是,该函数声明如下。

pub const fn null<T>() -> *const T
Run Code Online (Sandbox Code Playgroud)

在此声明中,T隐式假定具有固定大小(否则,它将是T: ?Sized)。因此,无法与*const str或一起使用此功能*const [u32]在操场上测试一下

是否有充分的理由排除未调整大小的类型?想要创建一个 null 有*const str什么问题?

pointers rust

5
推荐指数
1
解决办法
411
查看次数

如何在Jekyll站点中按原样复制子目录

我有一个网站; 我手动维护的一些页面,其他一些,我使用工具(主要是Shinx)生成.对于手动维护的页面,我想迁移到Jekyll.

所以我的想法是将我的整个网站复制到一个jekyll项目中,逐步将页面从静态HTML文件移动到jekyll管理的markdown文件,更容易维护.另一方面,生成的页面将不受影响地复制.

它工作得很好......除了Jekyll不复制以下划线开头的文件,我有很多:Sphinx用一个前导下划线(_static,_modules...)命名一些特殊目录,然后发布一些python代码,其中也使用前导下划线(例如 __init__.py).

我知道我可以使用该include指令_config.yml,并逐个添加我想保留的所有已知文件/目录.但我仍然冒险错过一些文件(特别是当我的发电机进化时).

我宁愿告诉Jekyll,对于每个生成的子目录,"这个目录应该按原样复制".这样可以防止它查看其中的每个文件以查看是否应该对其进行处理,因此任何以下划线开头的文件都会被盲目复制.

有没有办法做到这一点?我找不到任何......

jekyll

4
推荐指数
2
解决办法
1821
查看次数

为什么HashMap :: get_mut比HashMap更挑剔:: get关于生命周期?

我有一个参考struct Foo<'a>包装&'a str.我想HashMapFoos作为键来填充.这是一段代码(在操场上打开):

use std::collections::HashMap;

#[derive(PartialEq, Eq, Hash)]
struct Foo<'a> {
    txt: &'a str,
}

fn main() {
    let a = "hello".to_string();
    let a2 = Foo { txt: &a };
    let b = "hello".to_string();
    let b2 = Foo { txt: &b };

    let mut hm = HashMap::<Foo, u32>::new();

    hm.insert(a2, 42);
    println!("=== {:?}", hm.get(&b2));     // prints Some(42)
    println!("=== {:?}", hm.get_mut(&b2)); // prints Some(42)

    {
        let c = "hello".to_string();
        let c2 = …
Run Code Online (Sandbox Code Playgroud)

lifetime rust

4
推荐指数
1
解决办法
216
查看次数

为什么编译器不推断impl trait返回值的关联类型的具体类型?

我有一个关联类型的特征:

pub trait Speak {
    type Error;
    fn speak(&self) -> Result<String, Self::Error>;
}
Run Code Online (Sandbox Code Playgroud)

该特征的实现:

#[derive(Default)]
pub struct Dog;

impl Speak for Dog {
    type Error = ();
    fn speak(&self) -> Result<String, Self::Error> {
        Ok("woof".to_string())
    }
}
Run Code Online (Sandbox Code Playgroud)

并且函数返回该实现的实例:

pub fn speaker() -> impl Speak {
    Dog::default()
}
Run Code Online (Sandbox Code Playgroud)

我知道在这个例子中我只能Dog用作返回类型,但在我的实际代码中我必须使用impl Speak(上面的函数实际上是由宏生成的).

据我了解,该impl Trait符号让出这实际上返回具体类型编译器的身影,所以我希望下面的函数正确编译,因为speaker()回报Dog,并且Dog::Error是类型():

fn test() -> Result<String, ()> {
    speaker().speak()
}
Run Code Online (Sandbox Code Playgroud)

操场

相反,我收到以下错误:

error[E0308]: mismatched types
  --> src/lib.rs:21:5
   | …
Run Code Online (Sandbox Code Playgroud)

type-inference traits rust

1
推荐指数
1
解决办法
120
查看次数

为什么 len() 和 is_empty() 没有在特征中定义?

拉斯特大部分图案由性状(捕获IteratorFromBorrow,等)。

为什么像len/这样普遍的模式is_empty在标准库中没有相关特征?这会导致我无法预见的问题吗?被认为是无用的吗?或者只是没有人想到它(这似乎不太可能)?

traits rust

1
推荐指数
1
解决办法
538
查看次数