简体   繁体   English

将 &self 转换为 mut(在不是 mut 的地方使用预定义的特征)

[英]Cast &self to mut (to use predefined trait where it isn't mut)

I'm trying to implement Allocator:我正在尝试实现分配器:

pub unsafe trait Allocator {
    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
    ...

Note that the &self is not mutable.请注意, &self 是不可变的。 I'm not sure what kind of allocator would be able to allocate without making changes to the allocator itself, but this is what vec is prepared to talk to so I guess I have to put up with it.我不确定哪种分配器能够在不更改分配器本身的情况下进行分配,但这是vec准备与之交谈的,所以我想我必须忍受它。 My questions are:我的问题是:

  • should they have made the &self mut or am I missing something?他们应该使 &self mut 还是我错过了什么?
  • how do I brutally cast this &self to being mut?我如何残酷地将这个 &self 变成 mut ?

I tried just sticking mut in the impl:我试着在 impl 中加入 mut:

unsafe impl Allocator for Mappoc {                         
    fn allocate(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { 
    ...

but it said:但它说:

|| error[E0053]: method `allocate` has an incompatible type for trait
src/lib.rs|110| 17
||     |
|| 110 |     fn allocate(&mut self, layout: Layout)
||     |                 ^^^^^^^^^
||     |                 |
||     |                 types differ in mutability
||     |                 help: change the self-receiver type to match the trait: `self: &Mappoc`
||     |
||     = note: expected fn pointer `fn(&Mappoc, std::alloc::Layout) -> Result<_, _>`
||                found fn pointer `fn(&mut Mappoc, std::alloc::Layout) -> Result<_, _>`

In short, allocate() takes &self to allow the allocator to be used from multiple threads.简而言之, allocate()采用&self以允许从多个线程中使用分配器。 (Remember that a &mut reference is exclusive, only one may exist at a time.) The simplest thread-safe way to get a mutable reference out of an immutable one is by wrapping the actual allocator in a mutex: (请记住, &mut引用是独占的,一次只能存在一个。)从不可变引用中获取可变引用的最简单的线程安全方法是将实际分配器包装在互斥体中:

struct MappocAllocator {
    inner: Mutex<Mappoc>,  // your actual allocator
}

impl Allocator for MappocAllocator {
    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { 
        let alloc = self.inner.lock().unwrap();
        // now you have access to `&mut Mappoc` for the duration of the lock
        ...
    }
}

I'm not sure what kind of allocator would be able to allocate without making changes to the allocator itself我不确定在不对分配器本身进行更改的情况下能够分配哪种分配器

This is a misunderstanding of what &T means.这是对&T含义的误解。 A shared reference doesn't always imply that the data under it won't change, it means that it's safe to use by multiple actors at once.共享引用并不总是意味着它下面的数据不会改变,这意味着多个参与者一次使用它是安全的。 For example, lock-free mutating APIs always take &self .例如,无锁变异 API 总是采用&self

If the allocator you're actually using is written in Rust and is thread-safe (or partly/fully lock-free) itself, then its methods should take &self to begin with, and you won't need a mutex (because a mutex or its equivalent will be part of Mappoc implementation).如果您实际使用的分配器是用 Rust 编写的并且本身是线程安全的(或部分/完全无锁),那么它的方法应该以&self开头,并且您不需要互斥锁(因为互斥锁或其等价物将成为Mappoc实现的一部分)。 If Mappoc 's methods take &mut self , it means they're not safe to be invoked from multiple threads, and it's a good thing that Rust forces you to access them through a mutex.如果Mappoc的方法采用&mut self ,则意味着从多个线程调用它们是不安全的,Rust 强制您通过互斥体访问它们是一件好事。 This is the system working exactly as designed.这是完全按照设计工作的系统。

Finally, some allocators, like mimalloc or jemalloc , are implemented in C or C++ that does its own locking.最后,一些分配器,如mimallocjemalloc ,在 C 或 C++ 中实现,它们自己锁定。 But then their Rust fronts don't need &mut self either because they invoke the actual allocator through a raw pointer.但是他们的 Rust 前端也不需要&mut self因为它们通过原始指针调用实际的分配器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM