< 返回版块

Louys·Miaoa 豆沙饼 发表于 2022-10-01 09:16

想自己写一个struct, 想验证一下Cow的功能 写时复制,但是使用 Cow::from已经报错了. 请问怎么给struct A 实现Cow Trait? 请问rustup doc -- std, 怎么看Cow Trait 要怎么实现呢? 看了半小时, 一头雾水, 请各路大神教导一下

#![allow(dead_code, unused_imports)]
use std::{mem::transmute, borrow::Borrow};
struct A{
    a:String
}
// impl Into<Cow<'_, B:ToOwned+?Sized>> for A {
//     fn into(self) -> Cow<'_, B:ToOwned+?Sized> {
//         todo!()
//     }
// }
fn main(){
    let a = A{a:"ss".to_string()};
    let c:Cow<&A> = Cow::from(&a);
//怎么往下? 验证 写时复制
}

评论区

写评论
作者 Louys·Miaoa 豆沙饼 2022-10-01 15:17

感谢大佬, 按着你说的, 程序顺利编译通过了.再次感谢

--
👇
Grobycn: 用 Cow::Borrowed(&a), Cow::from 只有特定的一些类型实现了。 另外还需要 #[derive(Clone)]

作者 Louys·Miaoa 豆沙饼 2022-10-01 15:16

感谢大佬, 好像看懂了一点, 还是要继续努力

--
👇
苦瓜小仔:

首先看 Cow 定义

Cow 是个枚举体,而且带生命周期和类型泛型:

pub enum Cow<'a, B: ?Sized + 'a>
where
    B: ToOwned,
{
    Borrowed(&'a B),
    Owned(<B as ToOwned>::Owned),
}

所以它不是 trait。

它的概念很简单,总结几点:

  • 如果你创建 Cow::Borrowed 并且一直使用 &Cow,那么背后的数据为 &B
  • 如果你创建 Cow::Owned ,那么背后的数据为 <B as ToOwned>::Owned
  • 如果你创建 Cow::Borrowed 并且使用过一次 .to_mut(),那么背后的数据自动变成 <B as ToOwned>::Owned
  • Cow 是智能指针(只实现了 Deref),意味着可以直接读取背后的数据
    pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
        match *self {
            Borrowed(borrowed) => {
                *self = Owned(borrowed.to_owned());
                match *self {
                    Borrowed(..) => unreachable!(),
                    Owned(ref mut owned) => owned,
                }
            }
            Owned(ref mut owned) => owned,
        }
    }

B: ?Sized + 'a + ToOwned 约束了什么

?Sized 的含义是“编译时大小可能未知”,目的是支持 B 可能为 str[T] 或者 dyn Trait 等类型。

'a 表示这个数据必须存活 'a 那么长,所以意味着每次使用 Cow,必须遵循生命周期规则 —— 就算背后的数据已经转成了非借用的 <B as ToOwned>::Owned,也必须带生命周期 —— 从中拿到非借用(复制)的数据可使用 .into_owned(),该数据不带生命周期。

ToOwned借用概念下的 Clone trait,除了个别类型之外(str/[T]/Cstr/Path),基本可以认为任何实现 Clone 的类型都自动实现 ToOwned —— 你无需也无法手动实现 ToOwned

你的代码哪些问题

let c: Cow<&A> = Cow::from(&a); 显然没理解 Cow 的定义形式,Cow<'_, A> 才是对的。

枚举体的构造形式是一种最基本的构造函数 (所以遇到 .map(Cow::Borrowed) 时,别奇怪)。

Clone trait 也是一个构造前提, 这是 ToOwned 约束的。

苦瓜小仔 2022-10-01 11:29

首先看 Cow 定义

Cow 是个枚举体,而且带生命周期和类型泛型:

pub enum Cow<'a, B: ?Sized + 'a>
where
    B: ToOwned,
{
    Borrowed(&'a B),
    Owned(<B as ToOwned>::Owned),
}

所以它不是 trait。

它的概念很简单,总结几点:

  • 如果你创建 Cow::Borrowed 并且一直使用 &Cow,那么背后的数据为 &B
  • 如果你创建 Cow::Owned ,那么背后的数据为 <B as ToOwned>::Owned
  • 如果你创建 Cow::Borrowed 并且使用过一次 .to_mut(),那么背后的数据自动变成 <B as ToOwned>::Owned
  • Cow 是智能指针(只实现了 Deref),意味着可以直接读取背后的数据
    pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
        match *self {
            Borrowed(borrowed) => {
                *self = Owned(borrowed.to_owned());
                match *self {
                    Borrowed(..) => unreachable!(),
                    Owned(ref mut owned) => owned,
                }
            }
            Owned(ref mut owned) => owned,
        }
    }

B: ?Sized + 'a + ToOwned 约束了什么

?Sized 的含义是“编译时大小可能未知”,目的是支持 B 可能为 str[T] 或者 dyn Trait 等类型。

'a 表示这个数据必须存活 'a 那么长,所以意味着每次使用 Cow,必须遵循生命周期规则 —— 就算背后的数据已经转成了非借用的 <B as ToOwned>::Owned,也必须带生命周期 —— 从中拿到非借用(复制)的数据可使用 .into_owned(),该数据不带生命周期。

ToOwned借用概念下的 Clone trait,除了个别类型之外(str/[T]/Cstr/Path),基本可以认为任何实现 Clone 的类型都自动实现 ToOwned —— 你无需也无法手动实现 ToOwned

你的代码哪些问题

let c: Cow<&A> = Cow::from(&a); 显然没理解 Cow 的定义形式,Cow<'_, A> 才是对的。

枚举体的构造形式是一种最基本的构造函数 (所以遇到 .map(Cow::Borrowed) 时,别奇怪)。

Clone trait 也是一个构造前提, 这是 ToOwned 约束的。

Grobycn 2022-10-01 10:02

Cow::Borrowed(&a), Cow::from 只有特定的一些类型实现了。 另外还需要 #[derive(Clone)]

1 共 4 条评论, 1 页