国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【跟小嘉學(xué) Rust 編程】十五、智能指針

這篇具有很好參考價值的文章主要介紹了【跟小嘉學(xué) Rust 編程】十五、智能指針。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

系列文章目錄

【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ)
【跟小嘉學(xué) Rust 編程】二、Rust 包管理工具使用
【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念
【跟小嘉學(xué) Rust 編程】四、理解 Rust 的所有權(quán)概念
【跟小嘉學(xué) Rust 編程】五、使用結(jié)構(gòu)體關(guān)聯(lián)結(jié)構(gòu)化數(shù)據(jù)
【跟小嘉學(xué) Rust 編程】六、枚舉和模式匹配
【跟小嘉學(xué) Rust 編程】七、使用包(Packages)、單元包(Crates)和模塊(Module)來管理項目
【跟小嘉學(xué) Rust 編程】八、常見的集合
【跟小嘉學(xué) Rust 編程】九、錯誤處理(Error Handling)
【跟小嘉學(xué) Rust 編程】十一、編寫自動化測試
【跟小嘉學(xué) Rust 編程】十二、構(gòu)建一個命令行程序
【跟小嘉學(xué) Rust 編程】十三、函數(shù)式語言特性:迭代器和閉包
【跟小嘉學(xué) Rust 編程】十四、關(guān)于 Cargo 和 Crates.io
【跟小嘉學(xué) Rust 編程】十五、智能指針

前言

指針是一個包含了內(nèi)存地址的變量,該內(nèi)存地址引用或執(zhí)行了另外的數(shù)據(jù)。在Rust中最常見的指針類型就是引用。不同的是在Rust中引用被賦予更深的含義就是借用其他變量的值。

主要教材參考 《The Rust Programming Language》


一、智能指針

1.1、智能指針(smart point)

智能指針是一個復(fù)雜的數(shù)據(jù)結(jié)構(gòu),包含了比引用更多的信息,例如元數(shù)據(jù),當(dāng)前長度,最大可用長度等。

在之前章節(jié)實際上我們已經(jīng)見識過多種智能指針了,例如動態(tài)字符串 String 和動態(tài)數(shù)據(jù) Vec。

智能指針往往是基于結(jié)構(gòu)體實現(xiàn),它與我們自定義的結(jié)構(gòu)體最大的區(qū)別在于它實現(xiàn)了 Deref 和 Drop 特征:

  • Deref:可以讓智能指針像引用那樣工作,這樣你就可以寫出同時支持智能指針和引用的代碼,例如 *T
  • Drop:允許你就指定智能指針超出作用域后自動執(zhí)行的代碼,例如數(shù)據(jù)清理等收尾工作

1.2、Box 堆內(nèi)存分配

在Rust 中,所有值默認(rèn)都是在棧內(nèi)存上分配,通過創(chuàng)建 Box<T> 可用把值裝箱,使它在堆上分配。Box<T> 是一個智能指針,因為它實現(xiàn)了 Deref trait,它允許Box<T> 值被當(dāng)作引用對待,當(dāng) Box<T> 值離開作用域時,由于它實現(xiàn)了 Drop trait ,首先刪除其指向堆堆數(shù)據(jù),然后刪除自身。

使用場景

  • 在編譯時,某類型的大小無法確定,但使用該類型時,上下文卻需要知道它確切的大??;
  • 當(dāng)你有大量數(shù)據(jù),想移交所有權(quán),但需要確保在操作時數(shù)據(jù)不會被復(fù)制;
  • 使用某個值,你只關(guān)心它是否實現(xiàn)了特定的 trait ,而不關(guān)心它的具體類型;

1.2.1、場景1:堆內(nèi)存上分配數(shù)據(jù)


fn main() {
	let a = Box::new(1);  // Immutable
	println!("{}", a);    // Output: 1
	
	let mut b = Box::new(1);  // Mutable
	*b += 1;
	println!("{}", b);    // Output: 2
}

Box 的主要特性是單一所有權(quán),即同時智能有一個人擁有對其指向數(shù)據(jù)的所有權(quán),并且同時智能存在一個可變引用或多個不可變引用,這一點與Rust中其他屬于堆上的數(shù)據(jù)行為一致。

1.2.2、場景2: cons list

cons list 是來自 Lisp 語言的一種數(shù)據(jù)結(jié)構(gòu)。cons list 里面每個成員都包含兩個元素:當(dāng)前項都值和下一個元素。cons list 里的最后一個成員只包含一個 nil 值,沒有下一個元素。

Box<T> 是一個指針,Rust知道它需要多少空間,因為指針的大小不會基于它指向的數(shù)據(jù)的大小變化而變化。

use crate::List::{Cons, Nil};

fn main() {
    let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3,Box::new(Nil))))));
}

enum List {
    Cons(i32, Box<List>),
    Nil,
}

1.3、Deref 解引用

1.3.1、Deref trait

Deref Trait 允許我們重載解引用運算符 *。實現(xiàn) Deref 的智能指針可以被當(dāng)作引用來對待,也就是說可以對智能指針使用 *運算符來解引用。

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Deref for Box<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &**self
    }
}

1.3.2、三種 Deref 轉(zhuǎn)換

在之前,我們講的都是不可變的 Deref 轉(zhuǎn)換,實際上 Rust 還支持將一個可變的引用轉(zhuǎn)換成另一個可變的引用以及將一個可變引用轉(zhuǎn)換成不可變的引用,規(guī)則如下:

當(dāng) T: Deref<Target=U>,可以將 &T 轉(zhuǎn)換成 &U,也就是我們之前看到的例子
當(dāng) T: DerefMut<Target=U>,可以將 &mut T 轉(zhuǎn)換成 &mut U
當(dāng) T: Deref<Target=U>,可以將 &mut T 轉(zhuǎn)換成 &U

1.4、Drop 釋放資源

1.4.1、Drop trait

Drop trait 主要作用是釋放實現(xiàn)者實例擁有的資源,它只有一個方法 drop。當(dāng)實例離開作用域時會自動調(diào)用該方法,從而調(diào)用實現(xiàn)者指定的代碼。

#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<#[may_dangle] T: ?Sized> Drop for Box<T> {
    fn drop(&mut self) {
        // FIXME: Do nothing, drop is currently performed by compiler.
    }
}

1.4.2、使用 std::mem::drop 來提前 drop

Rust 不允許手動調(diào)用 Drop trait 的 drop 方法,但是可以 使用標(biāo)準(zhǔn)庫的 std::mem::drop 來提前 drop。

1.5、引用計數(shù)智能指針(RC<T> 和 Arc<T>)

1.5.1、RC<T>

RC<T> 主要用于同一個堆上所有分配的數(shù)據(jù)區(qū)域需要多個只讀訪問的情況,比起使用比起使用 Box<T> 然后創(chuàng)建多個不可變引用的方法更優(yōu)雅也更直觀一些,以及比起單一所有權(quán),Rc<T> 支持多所有權(quán)。

Rc 為 Reference Counter 的縮寫,即為引用計數(shù),Rust 的 Runtime 會實時記錄一個 Rc<T> 當(dāng)前被引用的次數(shù),并在引用計數(shù)歸零時對數(shù)據(jù)進(jìn)行釋放(類似 Python 的 GC 機制)。因為需要維護(hù)一個記錄 Rc<T> 類型被引用的次數(shù),所以這個實現(xiàn)需要 Runtime Cost。

use std::rc::Rc;

fn main() {
    let a = Rc::new(1);
    println!("count after creating a = {}", Rc::strong_count(&a));
    let b = Rc::clone(&a);
    println!("count after creating b = {}", Rc::strong_count(&a));
    {
        let c = Rc::clone(&a);
        println!("count after creating c = {}", Rc::strong_count(&a));
    }
    println!("count after c goes out of scope = {}", Rc::strong_count(&a));
}

需要注意

  • RC<T> 是完全不可變,可以理解為同一個內(nèi)存上的數(shù)據(jù)同時存在多個只讀指針
  • RC<T> 只適用單線程,盡管從概念上講不同線程間只讀指針是完全安全的,但是由于 RC<T> 沒有實現(xiàn)多個線程間保證計數(shù)一致性,如果你嘗試多線程內(nèi)使用,會報錯;

1.5.1、原子引用計數(shù)(Atomic reference counter)

此時引用計數(shù)就可以在不同線程中安全的被使用了。

use std::thread;
use std::sync::Arc;

fn main() {
    let a = Arc::new(1);
    thread::spawn(move || {
        let b = Arc::clone(&a);
        println!("{}", b);  // Output: 1
    }).join();
}

1.6、Cell 與 RefCell 內(nèi)部可變性

1.6.1、內(nèi)部可變性(interior mutability)

內(nèi)部可變性(interior mutability) 是 Rust 的設(shè)計模式之一,它允許你在只持有不可變引用的前提下對數(shù)據(jù)進(jìn)行修改,數(shù)據(jù)結(jié)構(gòu)中使用了 unsafe 代碼來繞過 Rust 正常的可變性和借用規(guī)則。

1.6.2、Cell

Cell 和 Refcell 在功能上沒有區(qū)別,區(qū)別在于 Cell 適用于 T 實現(xiàn) Copy 的情況

1.6.3、RefCell

由于 Cell 類型針對的是實現(xiàn)了 Copy 特征的值類型,因此在實際開發(fā)中,Cell 使用的并不多,因為我們要解決的往往是可變、不可變引用共存導(dǎo)致的問題,此時就需要借助于 RefCell 來達(dá)成目的。

Rust 規(guī)則 智能指針帶來的額外規(guī)則
一個數(shù)據(jù)只有一個所有者 Rc/Arc 讓一個數(shù)據(jù)可以擁有多個所有者
要么多個不可變借用,要么一個可變借用 RefCell 實現(xiàn)編譯器可變、不可變引用共存
違背規(guī)則導(dǎo)致編譯錯誤 違背規(guī)則導(dǎo)致運行時 panic

可以看出,Rc/Arc 和 RefCell 合在一起,解決了 Rust 中嚴(yán)苛的所有權(quán)和借用規(guī)則帶來的某些場景下難使用的問題。但是它們并不是銀彈,例如 RefCell 實際上并沒有解決可變引用和引用可以共存的問題,只是將報錯從編譯期推遲到運行時,從編譯器錯誤變成了 panic 異常:

1.6.4、Cell 和 RefCell

  • Cell 只適用于 Copy 類型,用于提供值,而RefCell 用于提供引用
  • Cell 不會panic ,而 RefCell 會
  • Cell 沒有額外的性能損耗

從 CPU 來看,損耗如下:

  • 對 Rc 解引用是免費的(編譯期),但是 * 帶來的間接取值并不免費
  • 克隆 Rc 需要將當(dāng)前的引用計數(shù)跟 0 和 usize::Max 進(jìn)行一次比較,然后將計數(shù)值加 1
  • 釋放(drop) Rc 需要將計數(shù)值減 1, 然后跟 0 進(jìn)行一次比較
  • 對 RefCell 進(jìn)行不可變借用,需要將 isize 類型的借用計數(shù)加 1,然后跟 0 進(jìn)行比較
  • 對 RefCell 的不可變借用進(jìn)行釋放,需要將 isize 減 1
  • 對 RefCell 的可變借用大致流程跟上面差不多,但是需要先跟 0 比較,然后再減 1
  • 對 RefCell 的可變借用進(jìn)行釋放,需要將 isize 加 1

1.6.5、解決借用沖突

在 Rust 1.37 版本中新增了兩個非常實用的方法:

  • Cell::from_mut,該方法將 &mut T 轉(zhuǎn)為 &Cell
  • Cell::as_slice_of_cells,該方法將 &Cell<[T]> 轉(zhuǎn)為 &[Cell]

1.7、Weak 和引用循環(huán)

1.7.1、引用循環(huán)和內(nèi)存泄漏

Rust 的內(nèi)存安全機制可以保證很難發(fā)生內(nèi)存泄漏。但是不代表不會內(nèi)存泄漏。一個典型的例子就是同時使用 Rc 和 RefCell 創(chuàng)建循環(huán)引用,最終這些引用的計數(shù)都無法被歸零,因此 Rc 擁有的值也不會被釋放清理。

use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;

#[derive(Debug)]
enum List {
    Cons(i32, RefCell<Rc<List>>),
    Nil,
}

impl List {
    fn tail(&self) -> Option<&RefCell<Rc<List>>> {
        match self {
            Cons(_, item) => Some(item),
            Nil => None,
        }
    }
}

fn main() {
    let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));

    println!("a的初始化rc計數(shù) = {}", Rc::strong_count(&a));
    println!("a指向的節(jié)點 = {:?}", a.tail());

    // 創(chuàng)建`b`到`a`的引用
    let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));

    println!("在b創(chuàng)建后,a的rc計數(shù) = {}", Rc::strong_count(&a));
    println!("b的初始化rc計數(shù) = {}", Rc::strong_count(&b));
    println!("b指向的節(jié)點 = {:?}", b.tail());

    // 利用RefCell的可變性,創(chuàng)建了`a`到`b`的引用
    if let Some(link) = a.tail() {
        *link.borrow_mut() = Rc::clone(&b);
    }

    println!("在更改a后,b的rc計數(shù) = {}", Rc::strong_count(&b));
    println!("在更改a后,a的rc計數(shù) = {}", Rc::strong_count(&a));

    // 下面一行println!將導(dǎo)致循環(huán)引用
    // 我們可憐的8MB大小的main線程??臻g將被它沖垮,最終造成棧溢出
    // println!("a next item = {:?}", a.tail());
}

如何防止循環(huán)引用

  • 開發(fā)者去注意細(xì)節(jié)
  • 使用 Weak

1.7.2、Weak

Weak 類似 RC 但是和 RC持有所有權(quán)不同,Weak 不必持有所有權(quán),僅僅保存一份指向數(shù)據(jù)的弱引用,如果你要想訪問數(shù)據(jù),需要通過 Weak 指針的 upgrade 方法實現(xiàn),該方法返回個類型為 Option<Rc<T>> 的值。

所謂弱引用就是不保證引用關(guān)系存在,如果不存在,就返回None。

因為 Weak 引用不計入所有權(quán),因此它無法阻止所引用的內(nèi)存值被釋放掉,而且 Weak 本身不對值的存在性做任何擔(dān)保,引用的值還存在就返回 Some,不存在就返回 None。

Weak RC
不計數(shù) 計數(shù)
不擁有所有權(quán) 擁有值的所有權(quán)
不阻止值被釋放(drop) 所有權(quán)計數(shù)歸零,才能drop
引用存在返回some,不存在返回None 引用值必定存在
通過 upgrade 取到Option<Rc<T>> 再取值 通過 Deref 自動解引用,取值無需任何操作

弱引用非常適合如下場景

  • 持有一個 Rc 對象的臨時引用,并且不在乎引用的值是否依然存在
  • 阻止 Rc 導(dǎo)致的循環(huán)引用,因為 Rc 的所有權(quán)機制,會導(dǎo)致多個 Rc 都無法計數(shù)歸零

1.7.3、unsafe

除了使用 Rust 標(biāo)準(zhǔn)庫提供的這些類型,你還可以使用 unsafe 里的裸指針來解決這些棘手的問題,但是由于我們還沒有講解 unsafe。

雖然 unsafe 不安全,但是在各種庫的代碼中依然很常見用它來實現(xiàn)自引用結(jié)構(gòu),主要優(yōu)點如下:

  • 性能高,畢竟直接用裸指針操作
  • 代碼更簡單更符合直覺: 對比下 Option<Rc<RefCell<Node>>>

總結(jié)

以上就是今天要講的內(nèi)容文章來源地址http://www.zghlxwxcb.cn/news/detail-674971.html

到了這里,關(guān)于【跟小嘉學(xué) Rust 編程】十五、智能指針的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【跟小嘉學(xué) Rust 編程】三十三、Rust的Web開發(fā)框架之一: Actix-Web的基礎(chǔ)

    【跟小嘉學(xué) Rust 編程】三十三、Rust的Web開發(fā)框架之一: Actix-Web的基礎(chǔ)

    【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ) 【跟小嘉學(xué) Rust 編程】二、Rust 包管理工具使用 【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念 【跟小嘉學(xué) Rust 編程】四、理解 Rust 的所有權(quán)概念 【跟小嘉學(xué) Rust 編程】五、使用結(jié)構(gòu)體關(guān)聯(lián)結(jié)構(gòu)化數(shù)據(jù) 【跟小嘉學(xué) Rust 編程】六、枚舉

    2024年02月04日
    瀏覽(28)
  • 【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ)

    【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ)

    【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ) 本系列旨在分享 Rust 學(xué)習(xí)心得,適合初學(xué)者入門,后續(xù)系列會有 Rust 項目實戰(zhàn)系列編程介紹。 主要教材參考 《The Rust Programming Language》 Rust 是一門新的編程語言,它可以讓每個人編寫可靠且高效的程序,使用于需要運行時速度、需要內(nèi)

    2024年02月10日
    瀏覽(18)
  • 【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念

    【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念

    【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ) 【跟小嘉學(xué) Rust 編程】二、Rust 包管理工具使用 【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念 本章節(jié)涵蓋幾乎所有編程語言會出現(xiàn)的概念以及他們在 Rust之中的工作原理,這不是 Rust 獨有的,但我們將在 Rust 上下文中討論他們,并且

    2024年02月10日
    瀏覽(21)
  • 【跟小嘉學(xué) Rust 編程】三十、Rust 使用 Slint UI

    【跟小嘉學(xué) Rust 編程】三十、Rust 使用 Slint UI

    【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ) 【跟小嘉學(xué) Rust 編程】二、Rust 包管理工具使用 【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念 【跟小嘉學(xué) Rust 編程】四、理解 Rust 的所有權(quán)概念 【跟小嘉學(xué) Rust 編程】五、使用結(jié)構(gòu)體關(guān)聯(lián)結(jié)構(gòu)化數(shù)據(jù) 【跟小嘉學(xué) Rust 編程】六、枚舉

    2024年02月04日
    瀏覽(26)
  • 【跟小嘉學(xué) Rust 編程】四、理解 Rust 的所有權(quán)概念

    【跟小嘉學(xué) Rust 編程】四、理解 Rust 的所有權(quán)概念

    【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ) 【跟小嘉學(xué) Rust 編程】二、Rust 包管理工具使用 【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念 【跟小嘉學(xué) Rust 編程】四、理解 Rust 的所有權(quán)概念 本章節(jié)將講解 Rust 獨有的概念(所有權(quán))。所有權(quán)是 Rust 最獨特的特性,它使得 Rust 能夠

    2024年02月10日
    瀏覽(30)
  • 【跟小嘉學(xué) Rust 編程】二十一、網(wǎng)絡(luò)編程

    【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ) 【跟小嘉學(xué) Rust 編程】二、Rust 包管理工具使用 【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念 【跟小嘉學(xué) Rust 編程】四、理解 Rust 的所有權(quán)概念 【跟小嘉學(xué) Rust 編程】五、使用結(jié)構(gòu)體關(guān)聯(lián)結(jié)構(gòu)化數(shù)據(jù) 【跟小嘉學(xué) Rust 編程】六、枚舉

    2024年02月10日
    瀏覽(19)
  • 【跟小嘉學(xué) Rust 編程】二十、進(jìn)階擴展

    【跟小嘉學(xué) Rust 編程】二十、進(jìn)階擴展

    【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ) 【跟小嘉學(xué) Rust 編程】二、Rust 包管理工具使用 【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念 【跟小嘉學(xué) Rust 編程】四、理解 Rust 的所有權(quán)概念 【跟小嘉學(xué) Rust 編程】五、使用結(jié)構(gòu)體關(guān)聯(lián)結(jié)構(gòu)化數(shù)據(jù) 【跟小嘉學(xué) Rust 編程】六、枚舉

    2024年02月10日
    瀏覽(20)
  • 【跟小嘉學(xué) Rust 編程】十九、高級特性

    【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ) 【跟小嘉學(xué) Rust 編程】二、Rust 包管理工具使用 【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念 【跟小嘉學(xué) Rust 編程】四、理解 Rust 的所有權(quán)概念 【跟小嘉學(xué) Rust 編程】五、使用結(jié)構(gòu)體關(guān)聯(lián)結(jié)構(gòu)化數(shù)據(jù) 【跟小嘉學(xué) Rust 編程】六、枚舉

    2024年02月10日
    瀏覽(20)
  • 【跟小嘉學(xué) Rust 編程】二十二、常用 API

    【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ) 【跟小嘉學(xué) Rust 編程】二、Rust 包管理工具使用 【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念 【跟小嘉學(xué) Rust 編程】四、理解 Rust 的所有權(quán)概念 【跟小嘉學(xué) Rust 編程】五、使用結(jié)構(gòu)體關(guān)聯(lián)結(jié)構(gòu)化數(shù)據(jù) 【跟小嘉學(xué) Rust 編程】六、枚舉

    2024年02月10日
    瀏覽(17)
  • 【跟小嘉學(xué) Rust 編程】六、枚舉和模式匹配

    【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ) 【跟小嘉學(xué) Rust 編程】二、Rust 包管理工具使用 【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念 【跟小嘉學(xué) Rust 編程】四、理解 Rust 的所有權(quán)概念 【跟小嘉學(xué) Rust 編程】五、使用結(jié)構(gòu)體關(guān)聯(lián)結(jié)構(gòu)化數(shù)據(jù) 【跟小嘉學(xué) Rust 編程】六、枚舉

    2024年02月13日
    瀏覽(32)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包