用CSS在不破坏一张图的内容的情况下 怎么把它放到比它小的div中

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用CSS在不破坏一张图的内容的情况下 怎么把它放到比它小的div中相关的知识,希望对你有一定的参考价值。

既然是比图片小的div,说明你设置了固定的宽高。
把图片宽高设置成百分比,如果想图片保持宽高比例,宽高设置一个就行
img
width:100%;
height:100%;
参考技术A 宽高用百分比,只设置一个就行 不然会变形 参考技术B 给那个小的div设施一个宽高,图片100%显示,高度自动就行了

如何在不破坏封装的情况下返回对 RefCell 内某些内容的引用?

【中文标题】如何在不破坏封装的情况下返回对 RefCell 内某些内容的引用?【英文标题】:How do I return a reference to something inside a RefCell without breaking encapsulation? 【发布时间】:2015-06-06 17:45:00 【问题描述】:

我有一个具有内部可变性的结构。

use std::cell::RefCell;

struct MutableInterior 
    hide_me: i32,
    vec: Vec<i32>,

struct Foo 
    //although not used in this particular snippet,
    //the motivating problem uses interior mutability
    //via RefCell.
    interior: RefCell<MutableInterior>,


impl Foo 
    pub fn get_items(&self) -> &Vec<i32> 
        &self.interior.borrow().vec
    


fn main() 
    let f = Foo 
        interior: RefCell::new(MutableInterior 
            vec: Vec::new(),
            hide_me: 2,
        ),
    ;
    let borrowed_f = &f;
    let items = borrowed_f.get_items();

产生错误:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:16:10
   |
16 |         &self.interior.borrow().vec
   |          ^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
17 |     
   |     - temporary value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 15:5...
  --> src/main.rs:15:5
   |
15 | /     pub fn get_items(&self) -> &Vec<i32> 
16 | |         &self.interior.borrow().vec
17 | |     
   | |_____^

问题是我不能在Foo 上拥有一个返回借用vec 的函数,因为借用的vec 仅在Ref 的生命周期内有效,但Ref 可以使用立即超出范围。

我认为Ref 必须坚持because:

RefCell&lt;T&gt; 使用 Rust 的生命周期来实现“动态借用”,这是一个可以声明对内部值的临时、独占、可变访问的过程。 RefCell&lt;T&gt;s 的借用是在“运行时”跟踪的,这与 Rust 的本地引用类型不同,后者在编译时完全静态跟踪。因为RefCell&lt;T&gt; 借用是动态的,所以可以尝试借用一个已经可变借用的值;发生这种情况时会导致任务恐慌。

现在我可以写一个这样的函数来返回整个内部:

pub fn get_mutable_interior(&self) -> std::cell::Ref<MutableInterior>;

但是,这可能会向Foo 公开真正私有的实现细节的字段(在此示例中为MutableInterior.hide_me)。

理想情况下,我只想公开vec 本身,可能带有一个守卫来实现动态借用行为。这样来电者就不必知道hide_me

【问题讨论】:

【参考方案1】:

您可以创建一个类似于 RefCell::borrow() 返回的 Ref&lt;'a,T&gt; 守卫的新结构,以包装此 Ref 并避免其超出范围,如下所示:

use std::cell::Ref;

struct FooGuard<'a> 
    guard: Ref<'a, MutableInterior>,

然后,您可以为它实现Deref trait,这样它就可以像&amp;Vec&lt;i32&gt; 一样使用:

use std::ops::Deref;

impl<'b> Deref for FooGuard<'b> 
    type Target = Vec<i32>;

    fn deref(&self) -> &Vec<i32> 
        &self.guard.vec
    

之后,更新您的 get_items() 方法以返回 FooGuard 实例:

impl Foo 
    pub fn get_items(&self) -> FooGuard 
        FooGuard 
            guard: self.interior.borrow(),
        
    

Deref 会变魔术:

fn main() 
    let f = Foo 
        interior: RefCell::new(MutableInterior 
            vec: Vec::new(),
            hide_me: 2,
        ),
    ;
    let borrowed_f = &f;
    let items = borrowed_f.get_items();
    let v: &Vec<i32> = &items;

【讨论】:

这是唯一/惯用的方法吗?似乎有点麻烦......虽然我想代替 getItems() 方法,您可以直接借用块中的内部结构,然后它会超出范围(或其他东西......) @Norcalli 在RefCell 的特定情况下,当引用超出范围时需要通知对象(这就是Ref 的析构函数所做的)。在这里,我们需要保留这种行为(OP的错误是由于Ref实例被过早丢弃),从而对其进行封装。【参考方案2】:

您可以使用Ref::map(从Rust 1.8 开始),而不是创建一个全新的类型。这与Levans' existing answer 的结果相同:

use std::cell::Ref;

impl Foo 
    pub fn get_items(&self) -> Ref<'_, Vec<i32>> 
        Ref::map(self.interior.borrow(), |mi| &mi.vec)
    

您还可以使用 impl Trait 等新功能从 API 中隐藏 Ref

use std::cell::Ref;
use std::ops::Deref;

impl Foo 
    pub fn get_items(&self) -> impl Deref<Target = Vec<i32>> + '_ 
        Ref::map(self.interior.borrow(), |mi| &mi.vec)
    

【讨论】:

如果你正在实现 std::ops::Index 特征,而不是 get_item ,这需要你返回 &Self::Output 。据我所知,返回 std::cell::Ref 不会满足特征要求。有没有办法针对该特征进行内部可变性? 其实我找到了一种使用 UnsafeCell 的方法,所以我认为这可能就足够了。 @DanielV Implementing Index trait to return a value that is not a reference。我不相信UnsafeCell 实现,因为它很可能会引入内存不安全。【参考方案3】:

您可以将Vec 包装在Rc 中。

use std::cell::RefCell;
use std::rc::Rc;

struct MutableInterior 
    hide_me: i32,
    vec: Rc<Vec<i32>>,

struct Foo 
    interior: RefCell<MutableInterior>,


impl Foo 
    pub fn get_items(&self) -> Rc<Vec<i32>> 
        self.interior.borrow().vec.clone() // clones the Rc, not the Vec
    


fn main() 
    let f = Foo 
        interior: RefCell::new(MutableInterior 
            vec: Rc::new(Vec::new()),
            hide_me: 2,
        ),
    ;
    let borrowed_f = &f;
    let items = borrowed_f.get_items();

当您需要改变Vec 时,使用Rc::make_mut 来获得对Vec 的可变引用。如果还有其他Rcs 引用Vecmake_mut 会将Rc 与其他Rcs 分离,克隆Vec 并更新自身以引用新的Vec,然后给你一个可变的引用。这确保了其他 Rcs 中的值不会突然改变(因为 Rc 本身不提供内部可变性)。

【讨论】:

以上是关于用CSS在不破坏一张图的内容的情况下 怎么把它放到比它小的div中的主要内容,如果未能解决你的问题,请参考以下文章

在不破坏 DropArea 的情况下拒绝拖放到 DropArea 中的外部文件

ps怎么把一张图抠出来的透明的

如何在不破坏布局“流程”的情况下使用 css 旋转元素?

如何在不破坏图像、CSS 和 JavaScript 的情况下实现友好的 URL? [关闭]

滚动锚定(Scroll Anchoring)- 让视口内容不再因视口上方 DOM 元素的高度变化而产生跳动

移动端上轮播图无缝滚动原理