Rust面試題及詳細答案120道(19-26)-- 所有權與借用

前后端面試題》專欄集合了前后端各個知識模塊的面試題,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。

前后端面試題-專欄總目錄

在這里插入圖片描述

文章目錄

  • 一、本文面試題目錄
      • 19. 簡述Rust的所有權(Ownership)規則,它解決了什么問題?
      • 20. 什么是移動(Move)語義?為什么Rust默認移動而非復制?
      • 21. 哪些類型實現了`Copy` trait?`Copy`與`Clone`的區別是什么?
        • 實現`Copy` trait的類型
        • `Copy`與`Clone`的區別
      • 22. 解釋借用(Borrowing)的概念,可變借用與不可變借用的規則是什么?
        • 不可變借用(`&T`)
        • 可變借用(`&mut T`)
      • 23. 為什么會出現“借用檢查器(Borrow Checker)”報錯?如何避免?
        • 常見報錯原因
        • 避免方法
      • 24. 什么是懸垂引用(Dangling Reference)?Rust如何防止這種情況?
        • Rust如何防止懸垂引用?
      • 25. 如何理解“引用的生命周期不能長于被引用值的生命周期”?
        • 原理說明
      • 26. 舉例說明同一作用域中,不可變引用與可變引用的共存限制。
        • 限制1:不可變引用存在時,不能創建可變引用
        • 限制2:可變引用存在時,不能創建不可變引用
        • 允許的情況:引用作用域分離
  • 二、120道Rust面試題目錄列表

一、本文面試題目錄

19. 簡述Rust的所有權(Ownership)規則,它解決了什么問題?

Rust的所有權(Ownership)是管理內存的核心機制,無需垃圾回收或手動內存管理即可保證內存安全,其核心規則如下:

  1. 每個值在Rust中都有一個所有者(Owner):同一時間只能有一個所有者。
  2. 當所有者離開作用域,值會被自動釋放:內存通過“作用域結束時調用drop函數”回收。
  3. 值的所有權可以轉移(Move):賦值或傳遞參數時,所有權從原變量轉移到新變量,原變量不再可用。

解決的問題

  • 內存安全問題:避免雙重釋放(同一內存被釋放兩次)和懸垂指針(引用已釋放的內存)。
  • 數據競爭問題:通過單一所有者限制,避免多線程同時修改數據。
  • 性能問題:無需垃圾回收的運行時開銷,內存釋放時機可預測。

示例

{let s = String::from("hello");  // s是"hello"的所有者let s2 = s;                     // 所有權從s轉移到s2,s不再可用// println!("{}", s);           // 編譯錯誤:s已失去所有權
}  // s2離開作用域,"hello"被自動釋放

20. 什么是移動(Move)語義?為什么Rust默認移動而非復制?

移動(Move)語義:當一個值被賦值給另一個變量(或傳遞給函數)時,所有權從原變量轉移到新變量,原變量不再擁有該值的訪問權(即“被移動”)。

示例

let v1 = vec![1, 2, 3];  // v1擁有向量的所有權
let v2 = v1;             // 向量所有權移動到v2,v1失效
// println!("{:?}", v1); // 編譯錯誤:v1已被移動

默認移動而非復制的原因

  1. 避免雙重釋放:堆上的數據(如StringVec)若默認復制,會導致兩個變量指向同一內存,離開作用域時雙重釋放。
  2. 明確內存管理:移動語義強制開發者顯式處理復制(通過Clone),避免意外的內存開銷。
  3. 性能優化:對于大型數據,復制操作成本高,移動僅轉移所有權(類似指針傳遞),更高效。

注意:棧上的簡單類型(如i32bool)因實現Copy trait,會默認復制而非移動(見第21題)。

21. 哪些類型實現了Copy trait?CopyClone的區別是什么?

實現Copy trait的類型

Copy trait用于標記可通過位復制(bit-for-bit copy)安全復制的類型,通常是棧上存儲的簡單類型:

  • 所有標量類型:i32u64f32boolchar等。
  • 包含Copy類型的元組:如(i32, bool)(若元組中所有元素都實現Copy)。
  • 不可變引用&T(但可變引用&mut T不實現Copy)。

示例

let x = 5;       // i32實現Copy
let y = x;       // 復制x的值給y,x仍可用
println!("x: {}, y: {}", x, y);  // 輸出:x: 5, y: 5
CopyClone的區別
特性Copy traitClone trait
復制方式隱式的位復制(編譯期自動完成)顯式的自定義復制(需調用clone()方法)
適用場景簡單類型(棧上數據)復雜類型(堆上數據,如StringVec
安全性必須是“無副作用”的復制可包含自定義邏輯(如深拷貝)
繼承關系實現Copy必須先實現Clone實現Clone無需Copy

示例

let s1 = String::from("hello");
// let s2 = s1;  // String未實現Copy,此處為移動,s1失效
let s2 = s1.clone();  // 顯式調用clone()復制,s1仍可用
println!("s1: {}, s2: {}", s1, s2);  // 輸出:s1: hello, s2: hello

22. 解釋借用(Borrowing)的概念,可變借用與不可變借用的規則是什么?

借用(Borrowing):允許通過引用(&T&mut T)臨時訪問值,而不獲取所有權。引用離開作用域后,值的所有權仍歸原變量。

不可變借用(&T
  • 通過&創建,允許讀取值但不能修改。
  • 規則:同一作用域內,可存在多個不可變引用(只讀共享)。

示例

let s = String::from("hello");
let r1 = &s;  // 不可變借用
let r2 = &s;  // 允許:多個不可變引用共存
println!("{} {}", r1, r2);  // 輸出:hello hello
可變借用(&mut T
  • 通過&mut創建,允許讀取和修改值。
  • 規則
    1. 同一作用域內,只能有一個可變引用(獨占訪問)。
    2. 可變引用與不可變引用不能同時存在(避免讀寫沖突)。

示例

let mut s = String::from("hello");
let r1 = &mut s;  // 可變借用
// let r2 = &mut s; // 錯誤:同一作用域只能有一個可變引用
r1.push_str(" world");
println!("{}", r1);  // 輸出:hello world// 可變引用與不可變引用不能共存
let r3 = &s;       // 不可變引用
// let r4 = &mut s; // 錯誤:已有不可變引用時不能創建可變引用

借用的核心目的:在保證內存安全的前提下,實現臨時訪問值,避免頻繁的所有權轉移。

23. 為什么會出現“借用檢查器(Borrow Checker)”報錯?如何避免?

借用檢查器(Borrow Checker) 是Rust編譯器的組件,用于在編譯期驗證引用的合法性,確保遵循借用規則(見第22題)。若違反規則,會產生編譯錯誤。

常見報錯原因
  1. 可變引用與不可變引用共存:同一作用域內同時存在可變引用和不可變引用。
  2. 多個可變引用共存:同一作用域內存在多個可變引用。
  3. 引用生命周期長于被引用值:引用指向的值已被釋放(懸垂引用)。

示例:借用檢查器報錯

let r;
{let x = 5;r = &x;  // 錯誤:x的生命周期短于r,r會成為懸垂引用
}
// println!("{}", r);
避免方法
  1. 縮小引用作用域:讓引用在被引用值釋放前失效。

    let x = 5;
    {let r = &x;  // r的作用域小于xprintln!("{}", r);
    }  // r失效,x仍有效
    
  2. 避免混合借用:在需要修改值時,確保沒有其他引用存在。

    let mut s = String::from("hello");
    {let r1 = &s;  // 不可變引用作用域受限
    }
    let r2 = &mut s;  // 此時無其他引用,允許創建可變引用
    
  3. 顯式轉移所有權:若無法通過借用解決,可通過clone()復制值或轉移所有權。

24. 什么是懸垂引用(Dangling Reference)?Rust如何防止這種情況?

懸垂引用(Dangling Reference):指向已被釋放內存的引用,訪問此類引用會導致未定義行為(如讀取無效數據)。

示例:其他語言可能出現的懸垂引用

// C語言示例(不安全)
int* dangling() {int x = 5;return &x;  // x離開作用域后被釋放,返回的指針成為懸垂指針
}
Rust如何防止懸垂引用?

Rust的生命周期系統借用檢查器在編譯期確保:

  1. 引用的生命周期不能長于被引用值的生命周期:編譯器會檢查引用的作用域是否在被引用值的作用域內。
  2. 值被釋放前,所有引用必須失效:當值離開作用域時,其所有引用已不可訪問。

Rust中的編譯期阻止

fn dangle() -> &String {  // 錯誤:缺少生命周期標注(實際編譯會更詳細)let s = String::from("hello");&s  // s的生命周期僅限于函數內,返回的引用會懸垂
}

正確做法:返回值的所有權而非引用,或確保被引用值的生命周期足夠長。

fn no_dangle() -> String {  // 返回所有權let s = String::from("hello");s
}

25. 如何理解“引用的生命周期不能長于被引用值的生命周期”?

“引用的生命周期不能長于被引用值的生命周期”是Rust內存安全的核心原則,可理解為:引用必須在被引用值釋放前失效,確保引用始終指向有效的內存。

原理說明
  • 生命周期(Lifetime):值在內存中存在的時間段(從創建到釋放)。
  • 若引用的生命周期長于被引用值,當值被釋放后,引用會成為懸垂引用,導致訪問無效內存。

示例:違反原則的情況

let r;                // r的生命周期開始
{let x = 5;        // x的生命周期開始r = &x;           // r引用x,但x的生命周期短于r
}                     // x的生命周期結束(被釋放)
// println!("{}", r); // 錯誤:r的生命周期長于x,訪問會導致懸垂引用

示例:遵循原則的情況

let x = 5;            // x的生命周期開始
let r = &x;           // r的生命周期開始,且短于x
println!("{}", r);    // 正確:r的生命周期在x的生命周期內
// x的生命周期結束,r的生命周期也已結束

編譯器的保證:Rust通過生命周期推斷和標注,在編譯期確保所有引用都遵循此原則,避免運行時錯誤。

26. 舉例說明同一作用域中,不可變引用與可變引用的共存限制。

Rust為避免數據競爭,嚴格限制同一作用域中不可變引用(&T)與可變引用(&mut T)的共存:不可變引用與可變引用不能同時存在,且同一時間只能有一個可變引用。

限制1:不可變引用存在時,不能創建可變引用
let mut s = String::from("hello");let r1 = &s;  // 不可變引用
let r2 = &s;  // 允許:多個不可變引用共存
// let r3 = &mut s; // 錯誤:已有不可變引用時,不能創建可變引用println!("{} and {}", r1, r2);  // 正確:使用不可變引用
限制2:可變引用存在時,不能創建不可變引用
let mut s = String::from("hello");let r1 = &mut s;  // 可變引用
// let r2 = &s;    // 錯誤:已有可變引用時,不能創建不可變引用
// let r3 = &mut s;// 錯誤:同一作用域只能有一個可變引用r1.push_str(" world");
println!("{}", r1);  // 正確:使用可變引用
允許的情況:引用作用域分離

若引用的作用域不重疊(通過代碼塊分隔),則可變引用和不可變引用可交替存在:

let mut s = String::from("hello");{let r1 = &mut s;  // 可變引用作用域限制在代碼塊內r1.push_str(" world");
}  // r1失效,不再有可變引用let r2 = &s;  // 此時可創建不可變引用
let r3 = &s;  // 多個不可變引用也允許
println!("{} and {}", r2, r3);  // 輸出:hello world and hello world

設計目的:防止“讀寫沖突”和“寫寫沖突”,確保多線程環境下的數據安全,是Rust無數據競爭并發的基礎。

二、120道Rust面試題目錄列表

文章序號Rust面試題120道
1Rust面試題及詳細答案120道(01-10)
2Rust面試題及詳細答案120道(11-18)
3Rust面試題及詳細答案120道(19-26)
4Rust面試題及詳細答案120道(27-32)
5Rust面試題及詳細答案120道(33-41)
6Rust面試題及詳細答案120道(42-50)
7Rust面試題及詳細答案120道(51-57)
8Rust面試題及詳細答案120道(58-65)
9Rust面試題及詳細答案120道(66-71)
10Rust面試題及詳細答案120道(72-80)
11Rust面試題及詳細答案120道(81-89)
12Rust面試題及詳細答案120道(90-98)
13Rust面試題及詳細答案120道(99-105)
14Rust面試題及詳細答案120道(106-114)
15Rust面試題及詳細答案120道(115-120)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/93057.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/93057.shtml
英文地址,請注明出處:http://en.pswp.cn/web/93057.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Jenkins + SonarQube 從原理到實戰三:SonarQube 打通 Windows AD(LDAP)認證與踩坑記錄

前言 在前兩篇文章中,已經介紹了 SonarQube 的部署 以及 通過 sonar-cxx 插件實現 C/C 代碼掃描。 本篇將重點講 如何讓 SonarQube 對接 Windows AD(LDAP),實現域賬號登錄和基于 AD 組的權限管理。 一、背景與需求分析 需求分析…

[AI React Web] 包與依賴管理 | `axios`庫 | `framer-motion`庫

第七章:包與依賴管理 在我們使用open-lovable的旅程中,已經探索了它如何管理對話狀態(第一章:對話狀態管理)、將創意轉化為可運行代碼(第二章:AI代碼生成管道)、如何在安全的虛擬環…

PanSou 一款開源網盤搜索項目,集成前后端,一鍵部署,開箱即用

PanSou 網盤搜索API PanSou是一個高性能的網盤資源搜索API服務,支持TG搜索和自定義插件搜索。系統設計以性能和可擴展性為核心,支持并發搜索、結果智能排序和網盤類型分類。 項目地址:https://github.com/fish2018/pansou 特性&#xff08…

java爬蟲實戰

本人目前在做魚皮的《智能協同云圖庫》,涉及到了以圖搜圖圖片爬取,雖然以前有爬過圖片,但是用的都是別人現成的代碼,不怎么去理解為什么要這樣做,這次有在嘗試理解每一個步驟。本人基礎極差,屬于一點基礎也…

深入詳解C語言的循環結構:while循環、do-while循環、for循環,結合實例,講透C語言的循環結構

🔥個人主頁:艾莉絲努力練劍 ?專欄傳送門:《C語言》、《數據結構與算法》、C語言刷題12天IO強訓、LeetCode代碼強化刷題、C/C干貨分享&學習過程記錄 🍉學習方向:C/C方向 ??人生格言:為天地立心&#…

北京-4年功能測試2年空窗-報培訓班學測開-第七十四天-線下面試-聊的很滿意但可能有風險-等信吧

今天沒去教室,因為下午有個線下面試。其實是可以去教室的,但我實在太焦慮了,我覺得去了教室我心情會更不好,什么都干不下去,所以我選擇不去早上依舊是帶著滿滿焦慮起來的,會覺得自己的一切都不令自己滿意&a…

在ubuntu服務器下安裝cuda和cudnn(筆記)

目錄 0 引言 1 相關環境查詢 2 安裝cuda 2.1 下載并安裝 2.2 安裝選項配置 2.3 驗證安裝 3 安裝cudnn 3.1 下載 3.2 解壓 3.3 刪除舊版本 cuDNN 3.4 復制新文件到 CUDA 目錄 3.5 設置文件權限 3.6 創建軟鏈接 3.7 驗證安裝 0 引言 我在使用服務器的cuda11.8的時…

docker安裝centos

docker庫地址https://hub.docker.com/ 嘗試使用centos7試了幾次超時 換了個版本就可以了 docker pull centos:centos7.9.2009有時候需要更新資源地址 可以使用 vim /etc/docker/daemon.json配置其他資源地址 {"registry-mirrors": ["http://hub-mirror.c.163…

內容索引之word轉md工具 - markitdown

切分文檔構建RAG庫過程中,langchain、llamaindex更期望處理latex、md類帶有顯式結構文檔。 langchain、llamaindex切分word,有可能將段落中間截斷,導致切分后的塊語義不完整。 所以,需要先將word轉化為md格式,然后再…

MaxKB+合合信息TextIn:通過API實現PDF掃描件的文檔審核

上海合合信息科技股份有限公司(以下簡稱為合合信息)是一家深耕人工智能、OCR(光學字符識別)及商業大數據技術領域的科技企業。該公司擁有領先的智能文字識別技術,其名片全能王(CamCard)、掃描全…

MyBatis 核心入門:從概念到實戰,一篇掌握簡單增刪改查

目錄 一、什么是 MyBatis?為什么要用它? 二、MyBatis 核心概念(通俗理解) 1.SqlSessionFactory 2.SqlSession 3.Mapper接口 4.映射文件(XML) 三、手把手搭建第一個 MyBatis 項目 1. 準備工作 2. 核心配置文…

數據結構初階(12)排序算法—插入排序(插入、希爾)(動圖演示)

2. 常見排序算法的實現2.0 十大排序算法2.1 插入排序 2.1.1 基本思想直接插入排序是一種簡單的插入排序法:基本思想把待排序的記錄按其關鍵碼值的大小逐個插入到一個已經排好序的有序序列中。直到所有的記錄插入完為止,得到一個新的有序序列 。 比 挪 (…

MySQL優化常用的幾個方法

本實例是對慢sql從2萬優化到5千優化方法的匯總。 首先貼上優化效果:1、更新數據時使用ID更新;2、"分頁/輪詢"查詢時先獲取符合數據要求主鍵的最大和最小ID,然后WHERE條件增加ID步增查詢;3、檢查SQL是否命中WHERE條件&am…

深入解析 AUTOSAR:汽車軟件開發的革命性架構

引言在汽車智能化、網聯化、電動化浪潮席卷全球的今天,汽車電子系統的復雜性與日俱增。傳統“煙囪式”的 ECU 開發模式(各供應商獨立開發軟硬件)帶來了巨大的兼容性、復用性和維護成本挑戰。AUTOSAR(AUTomotive Open System ARchi…

計算機視覺(opencv)實戰一——圖像本質、數字矩陣、RGB + 圖片基本操作(灰度、裁剪、替換等)

OpenCV 入門教程: OpenCV(Open Source Computer Vision Library)是一個開源的計算機視覺庫,廣泛應用于圖像處理、視頻分析、機器學習等領域。 在 Python 中,cv2 是 OpenCV 的主要接口模塊。本文將帶你一步步掌握 cv2…

《探索C++ set與multiset容器:深入有序唯一性集合的實現與應用》

前引:在STL的關聯式容器中,set以其嚴格的元素唯一性和自動排序特性成為處理有序數據的核心工具。其底層基于紅黑樹(Red-Black Tree)實現,保證了O(log n)的查找、插入與刪除復雜度!本文將從底層原理切入&…

各測試平臺功能對比分析(ITP,Postman,Apifox,MeterSphere)

對比ITP與Postman,Apifox,MeterSphere 功能特性ITPPostmanApifoxMeterSphere接口測試? 可視化接口調試,支持多種請求方式? 支持? 支持? 支持場景測試? 多接口串聯測試,支持前后置腳本? Collections功能? 支持? 支持定時任務? 基于Celery的定時…

開源日志log4cplus—如何將 string類型轉為tstring類型,又如何將char*類型轉換為tstring類型?

文章目錄🔧 一、理解 log4cplus::tstring 的本質?? 二、std::string 轉 tstring 的三種方法? 1. 使用內置宏 LOG4CPLUS_STRING_TO_TSTRING(推薦)? 2. 手動條件編譯轉換(精細控制)? 3. 多字節模式下的直接賦值??…

深度學習之CNN網絡簡介

CNN網絡簡單介紹 1.概述 卷積神經網絡(Convolutional Neural Network,CNN)是一種專門用于處理具有網格狀結構數據的深度學習模型。 ? CNN網絡主要有三部分構成:卷積層、池化層和全連接層構成,其中卷積層負責提取圖像中…

【微實驗】基頻提取的MATLAB實現(優化版)

前情提要: 【超詳細】科普:別再只會用自相關!YIN 和 PYIN 如何破解音頻隱藏密碼?-CSDN博客 【微實驗】媽媽我的MATLAB會識別聲音的基頻了!-CSDN博客 今天用MATLAB把算法封裝成函數,然后調用對比結果。 …