< 返回版块

Ark 发表于 2020-06-29 20:38

playground链接在这

不方便访问的话直接贴出来:

fn main() {
    let mut buf = Buffer::new(vec![1,2,3, 4, 5,6]);
    // let b1 = buf.read_bytes();
    let b1 = &buf.read_bytes().to_owned();
    let b2 = buf.read_bytes();
    print(b1,b2)
}

fn print(b1 :&[u8], b2: &[u8]) {
    println!("{:#?} {:#?}", b1, b2)
}

struct Buffer {
    buf: Vec<u8>,
    pos: usize,
}

impl Buffer {
    fn new(b: Vec<u8>) -> Buffer {
        Buffer {
            buf: b,
            pos: 0,
        }
    }

    fn read_bytes(&mut self) -> &[u8] {
        self.pos += 3;
        &self.buf[self.pos-3..self.pos]
    }
}

b1变量不能如注释所写,会报mut二次借用,只能赋予所有权后引用传给print()

这个错是因为read_bytes()使用了可变引用,但其实返回的buf可以是不可变借用的,就不知该如何实现这个功能。

评论区

写评论
whfuyn 2020-07-01 02:56

&mut self本身调用完就结束了啊,不会一直存在,当然返回的新引用另算。

@xiaopengli89和@laizy的代码我疑惑了很久,从可变引用中弄出不可变引用且存在多个居然不会报错,后来想明白了,这是因为buffer里存的是数组的不可变引用而不是数组本身,而不可变引用是Copy的,对于&mut selfself.buf直接就得到了一个不可变引用,而不需要间接经过&mut self

不知道我这么理解对吗?

--
👇
linuxwyn: 老哥,你这个简单清晰,。但我有一点不明白的就是,为什么带生命周期的Buffer结构体在一个作用域内可以有两个可变引用呢,read_bytes函数的签名也还是&mut self啊?麻烦老哥指点一二

--
👇
xiaopengli89: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7a55943515bfb0268d5011d9fedb0150

data是数据,b1和b2都是对data的immutable借用,lifetime要明确他们的关系;而buf是一个游标,它是mutable的

linuxwyn 2020-06-30 23:22

老哥,你这个简单清晰,。但我有一点不明白的就是,为什么带生命周期的Buffer结构体在一个作用域内可以有两个可变引用呢,read_bytes函数的签名也还是&mut self啊?麻烦老哥指点一二

--
👇
xiaopengli89: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7a55943515bfb0268d5011d9fedb0150

data是数据,b1和b2都是对data的immutable借用,lifetime要明确他们的关系;而buf是一个游标,它是mutable的

laizy 2020-06-30 20:12

不需要unsafe的写法, https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b1be3e206cdf64e482c083648478c9ae

之前知乎上写了篇类似的文章供参考:https://zhuanlan.zhihu.com/p/104742696

xiaopengli89 2020-06-30 19:03

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7a55943515bfb0268d5011d9fedb0150

data是数据,b1和b2都是对data的immutable借用,lifetime要明确他们的关系;而buf是一个游标,它是mutable的

linuxwyn 2020-06-30 11:52

直接unsafe

struct Buffer {
    buf: Vec<u8>,
    pos: usize,
}

impl Buffer {
    fn new(b: Vec<u8>) -> Self {
        Buffer { buf: b, pos: 0 }
    }

    fn read_bytes(&mut self) -> &[u8] {
        self.pos += 3;
        &self.buf[self.pos - 3..self.pos]
    }
}

fn print(b1: &[u8], b2: &[u8]) {
    println!("{:#?}\n{:#?}", b1, b2);
}

fn main() {
    let mut buf = Buffer::new(vec![1, 2, 3, 4, 5, 6]);
    let ptr = &mut buf as *mut Buffer;
    unsafe {
        let b1 = ptr.as_mut().unwrap().read_bytes();
        let b2 = ptr.as_mut().unwrap().read_bytes();
        print(b1,b2);
    }
}
作者 Ark 2020-06-30 08:52

感谢。

--
👇
whfuyn: 另外这里报多次可变借用的原因是read_bytes返回的不可变引用是从可变引用中拿出来的,这样的引用相当于一个不可以通过它修改的可变引用,同时拥有两者的缺点又失去了各自的优点。

whfuyn 2020-06-30 01:39

另外这里报多次可变借用的原因是read_bytes返回的不可变引用是从可变引用中拿出来的,这样的引用相当于一个不可以通过它修改的可变引用,同时拥有两者的缺点又失去了各自的优点。

whfuyn 2020-06-30 01:31

用Cell,这样:


use std::cell::Cell;

fn main() {
    let buf = Buffer::new(vec![1,2,3, 4, 5,6]);
    let b1 = buf.read_bytes();
    // let b1 = &buf.read_bytes().to_owned();
    let b2 = buf.read_bytes();
    print(b1,b2)
}

fn print(b1 :&[u8], b2: &[u8]) {
    println!("{:#?} {:#?}", b1, b2)
}

struct Buffer {
    buf: Vec<u8>,
    pos: Cell<usize>,
}

impl Buffer {
    fn new(b: Vec<u8>) -> Buffer {
        Buffer {
            buf: b,
            pos: Cell::new(0),
        }
    }

    fn read_bytes(&self) -> &[u8] {
        let new_pos = self.pos.get() + 3;
        self.pos.set(new_pos);
        &self.buf[new_pos-3..new_pos]
    }
}
作者 Ark 2020-06-29 21:47

嗯 我去瞅瞅。

--
👇
Neutron3529: 另有一种方法大概是把pos改成“内部可变”的形式,比如Box,然后在保证Box不变的同时可以改Box里面的值,从而只需要&self而非&mut self

你或许可以看看slice关于windows或者chunks这两个函数的实现

虽不知有没有用但我只会这么多了……

作者 Ark 2020-06-29 21:47

好的 感谢。

--
👇
gwy15: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=42935974e83d10f8ab1a76af8496f88a

fn main() {
    let buf = Buffer::new(vec![1,2,3, 4,5,6]);
    
    let mut iter = buf.every(3);
    let b1 = iter.next().unwrap();
    let b2 = iter.next().unwrap();
    print(b1,b2);

    // or
    for b in buf.every(3) {
        print(b, b);
    }
}

用迭代器更方便一点,分离数据和操作(算法)

Neutron3529 2020-06-29 21:42

另有一种方法大概是把pos改成“内部可变”的形式,比如Box,然后在保证Box不变的同时可以改Box里面的值,从而只需要&self而非&mut self

你或许可以看看slice关于windows或者chunks这两个函数的实现

虽不知有没有用但我只会这么多了……

Neutron3529 2020-06-29 21:38

我并不会写Struct

只好这样改了

fn main() {
    let buf = vec![1,2,3, 4, 5,6];
    let res:Vec<&[u8]>=buf.as_slice().chunks(3).take(2).collect();
    //let res:Vec<&[u8]>=buf.as_slice().chunks(3).collect();//这样也可以达到相同的效果
    //let res:Vec<&[u8]>=buf.as_slice().chunks_exact(3).collect();//可以确保res里面的slice的长度都是3,剩下部分好像需要一个remain函数,但我懒得查文档了。
    print(res[0],res[1])
}

fn print(b1 :&[u8], b2: &[u8]) {
    println!("{:#?} {:#?}", b1, b2)
}
lineCode 2020-06-29 21:30

可以用Cell吧

gwy15 2020-06-29 21:30

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=42935974e83d10f8ab1a76af8496f88a

fn main() {
    let buf = Buffer::new(vec![1,2,3, 4,5,6]);
    
    let mut iter = buf.every(3);
    let b1 = iter.next().unwrap();
    let b2 = iter.next().unwrap();
    print(b1,b2);

    // or
    for b in buf.every(3) {
        print(b, b);
    }
}

用迭代器更方便一点,分离数据和操作(算法)

1 共 14 条评论, 1 页