使用lldb查看Rust不同類型的結構

目錄

前言

正文

標量類型

復合類型——元組

?復合類型——數組

函數

&str

struct

可變數組vec

Iter

String

Box

Rc

Arc

?RefCell

Mutex

RwLock

Channel

總結


前言

筆者發現這個lldb挺好玩的,可以查看不同類型的結構,雖然這好像是C++的東西,

看看Rust的也可以,

筆者使用RustRover中的調試模式,在后面的代碼,在打印語句哪一行打斷點。

輸出使用

expr??? <變量>

正文

參考如下

數據類型 - Rust 程序設計語言 中文版Rust 程序設計語言中文也譯為 Rust 權威指南,是 Rust 官方推出的學習 Rust 的必備教程。Rust Wiki 版的 Rust 程序設計語言簡體中文版將由 Rust 中文翻譯項目組持續維護和更新,確保內容最新最全。https://www.rustwiki.org.cn/zh-CN/book/ch03-02-data-types.html

標量類型

標量scalar)類型表示單個值。Rust 有 4 個基本的標量類型:整型、浮點型、布爾型和字符

比如

    let a=1;println!("{a}")

輸出

(lldb) expr a
(i32) a = 1

i32表示是32為的整數,當前值為1

獲取其地址

(lldb) expr &a
(*mut i32) &a = 0x000000839274f5f4

加個引用符號。

對于其他類似的,比如u32,u8、true等,這些標量類型都是放在某一個地址中,沒有其他東西。

使用其他命令——frame variable -L

(lldb) frame variable -L a0x000000d6151df964: (i32) a = 1

可以看到輸出了地址、類型、變量、值。

在tauri中沒有什么區別。

復合類型——元組

看看元組內部長什么樣的

比如

    let a=(1,2.0,'g');println!("{a:?}")

輸出

(lldb) expr a
(tuple$<i32,f64,char>) a = (__0 = 1, __1 = 2, __2 = 'g')

可以使用 .0或者__0訪問其中的數據

(lldb) expr a.__0
(i32) __0 = 1
(lldb) expr a.0
(i32) __0 = 1

看來這個元組是多個標量和在一起的類型

在rust代碼中,無法使用 __0

類型 `(i32, f64, char)` 中沒有字段 `__0` [E0609]

?在tauri中沒有什么區別。

?復合類型——數組

    let a=[1,2,3];println!("{a:?}")

輸出

(lldb) expr a
([i32; 3]) a = ([0] = 1, [1] = 2, [2] = 3)

這里是i32類型,長度為3的數組。

在lldb訪問其中的值,可以使用a[0],也可以使用a.0

(lldb) expr a[0]
(i32) [0] = 1
(lldb) expr a.0
(i32) [0] = 1

函數

如果是一個函數

fn f1()->i32{return 1; 
}
fn main() {let a=f1;println!("123");}

a會是什么? 輸出看看

(lldb) expr a
(*mut ) a = 0x0000000011117b00

*mut 表示是一個可變的指針

筆者想調用a,但是沒成功

(lldb) expr a()
error: function call failed

不知道什么情況。

&str

    let x="abc";println!("{x}");

換個字母。

看看&str的在lldb的輸出

(lldb) expr x
(ref$<str$>) x = "abc" {data_ptr = 0x00007ff791a1a3b0length = 3
}

有兩個東西,筆者都不知道改怎么稱呼,就叫 字段,

有兩個字段,一個data_ptr,顯而易見,是存放數據的地址,可以修改

另一個length,就是長度了。

進去地址看看

(lldb) expr x.data_ptr
(*mut u8) data_ptr = 0x00007ff791a1a3b0

?發現又是是個可變指針,指向一個u8類型的內存地址

可以加個*訪問了

(lldb) expr *(x.data_ptr)
(u8) *data_ptr = 97

發現是97,這不就是a的ASCLL碼,

訪問一下其他的

(lldb) expr *x.data_ptr+1
(u32)  = 98
(lldb) expr *x.data_ptr+2
(u32)  = 99

沒問題。

筆者本來想修改數據的,沒想到失敗了

(lldb) memory region x.data_ptr
[0x00007ff688860000-0x00007ff688883000) r--

memory region 是 LLDB 調試器中的一個命令,

用于顯示指定內存地址所在的內存區域的屬性和權限信息。

它會告訴你某個地址是否可讀、可寫、可執行,以及該內存區域的起始和結束范圍。

可以發現,只有r,只有只讀

筆者就算在變量設置mut,內存還是還是只讀

但是,可以修改長度

(lldb) expr (x).length=1
(u64) length = 1

總之,這個&str就像一個“結構體”,感覺不是很準確,應該說像“json”。

筆者發現tauri 通信函數greet

#[command]
fn greet(name: &str) -> String {println!("Hello, {}!", name);format!("Hello, {}! You've been greeted from Rust!", name)
}

這個name,內存居然擁有寫的權限

(ref$<str$>) name = "world" {data_ptr = 0x000001b36114b6f0length = 5
}
(lldb) memory region 0x000001b36114b6f0
[0x000001b361050000-0x000001b36114f000) rw-

筆者不能理解?

struct

看看結構體

如下,

    struct book<'a>{id: i32,name:&'a str,}let book1 = book{id: 1,name: "rust",};println!("{}", book1.name);

輸出

(lldb) expr book1
(shared_state_concurrency::main::book) book1 = {id = 1name = "rust" {data_ptr = 0x00007ff7d53fa3b0length = 4}
}

真像json,比如取值——length

(lldb) expr book1.name.length
(u64) length = 4

沒問題

可變數組vec

    let a=vec![1, 2, 3];println!("{:?}", a);

輸出

(lldb) expr a
(alloc::vec::Vec<i32,alloc::alloc::Global>) a = size=3 {[0] = 1[1] = 2[2] = 3
}

獲取第一個字段——buf,a.0、a[0]、或者a.buf,都行

(lldb) expr a.buf
(alloc::raw_vec::RawVec<i32,alloc::alloc::Global>) buf = {inner = {ptr = {pointer = {pointer = 0x000002b284ccfc20}_marker = {}}cap = (__0 = 3)alloc = {}}_marker = {}
}

看看這個地址可不可以寫

(lldb) memory region 0x000002b284ccfc20
[0x000002b284cb0000-0x000002b284cd0000) rw-

?發現有w,可以寫,改成66 77 88。

修改數據

memory write -s 4 0x000001d9e06a7430 42 4d 58

因為是i32類型的,32位,需要4個字節,

66是十進制,變成16進制是42

其他同理。寫完后

(lldb) expr a(alloc::vec::Vec<i32,alloc::alloc::Global>) a = size=3 {[0] = 66[1] = 77[2] = 88
}

沒問題

Iter

看看迭代器

    let a=vec![1,2,3];let iter= a.iter();println!("{a:?}")

如果以json數據表示iter的結構,如下

{"iter": {"ptr": {"pointer": "0x000001dd45d299f0"},"end_or_len": "0x000001dd45d299fc","_marker": {}}
}

發現這個iter,pointer和?end_or_len都是地址,

意思就很明顯了,從pointer開始,到end_or_len結束。

f0到fc ,中間有12個字節,類型是i32的,沒問題。

String

    let a=String::from("hello");println!("{:?}", a);

輸出

(lldb) expr a
(alloc::string::String) a = "hello" {vec = size=5 {[0] = 104[1] = 101[2] = 108[3] = 108[4] = 111}
}

可以看到String里面放了一個vec,

(lldb) expr a.vec
(alloc::vec::Vec<u8,alloc::alloc::Global>) vec = size=5 {[0] = 104[1] = 101[2] = 108[3] = 108[4] = 111
}

這個vec元素的類型還是u8。

如果考慮成json結構,可能是這樣的

{"a":{"vec": {"buf": {"inner": {"ptr": {"pointer": {"pointer": "0x000001651effdeb0"},"_marker": {}},"cap": {"__0": 5},"alloc": {}},"_marker": {}},"len": 5}}
}

沒問題

Box

Box是智能指針,允許將一個值放在堆上而不是棧上

    let a=Box::new(1);println!("{:?}", a);

輸出,看看a長什么樣

(lldb) expr a
(*mut i32) a = 0x00000279d903de90

確實是一個指針

獲取其中的值*a

(lldb) memory region 0x00000279d903de90
error: 'jb_renderers_set_markup' is not a valid command.
[0x00000279d9030000-0x00000279d9050000) rw-

有寫的權限?

Rc

Rc被稱為?引用計數

    let a=Rc::new(1);println!("{:?}", a);

輸出?

(lldb) expr  a
(alloc::rc::Rc<i32,alloc::alloc::Global>) a = strong=1, weak=0 {value = 1
}

這個Rc就比Box要復雜的得多

使用json表示內部的結構

{"a:rc":{"ptr": {"pointer":{"strong":{"value": {"value": 1}},"weak":{"value": {"value": 1}},"value":1}},"phantom":{},"alloc": {}}
}

表示的不是很準確,因為pointer其實是一個指針。

(lldb) expr a.ptr.pointer
(*mut alloc::rc::RcInner<i32>) pointer = 0x000001eb490a7710

擁有寫的權限


(lldb) memory region 0x000001eb490a7710
[0x000001eb49090000-0x000001eb490b0000) rw-

使用一次clone,

let b=Rc::clone(&a);

發現strong變成了2

(lldb) expr a.ptr.pointer.strong.value.value
(u64) value = 2

Arc

Arc原子引用計數指針,可以安全地在多線程環境中共享數據

結構和Rc幾乎一模一樣,但是其中的類型不一樣。筆者就不展示了

?RefCell

允許你即使在有不可變引用時也可以改變數據

    let a=RefCell::new(1);println!("{:?}", a);

輸出用json表示

  "a:RefCell":{"value": {"value": 1},"borrowed": {"value": {"value": 0}}}

這個RefCell 有點高級,筆者沒有看到關于地址的東西

使用一下

    {let mut b=a.borrow_mut();*b=2;println!("{:?}", a);}

在大括號里面,發現這個a的borrow的值

(lldb) expr a.borrow.value.value
(i64) value = -1

居然變成了-1,有點意思

Mutex

看看互斥鎖

    let a=Mutex::new(1);println!("{a:?}")

輸出,用json表示結構

{"a:Mutex":{"inner": {"futex": {"v": {"value": 0}}},"poison": {"failed": {"v": {"value": 0}}},"data": {"value": 1}}
}

如果使用了lock

let lock=a.lock().unwrap();

可以發現futex的值變成了1

(lldb) expr a.inner.futex.v.value
(u8) value = 1

RwLock

    let a=RwLock::new(1);println!("{a:?}")

其結構用json表示

{"a:RwLock": {"inner": {"state": {"v": {"value": 0}},"writer_notify": {"v": {"value": 0}}},"poison": {"failed": {"v": {"value": 0}}},"data": {"value": 1}}
}

和Mutex差不多,但是inner內部變了

很容易猜測,使用一次讀鎖,state對應的值變成1

使用一次寫鎖writer_notify對應的值變成1

但是,筆者使用讀鎖,確實如下

 let b=a.read().unwrap();
(lldb) expr a.inner.state.v.value
(u32) value = 1

使用寫鎖

let mut b=a.write().unwrap();

發現并不是writer_notify變成1

(lldb) expr a
(std::sync::poison::rwlock::RwLock<i32>) a = {inner = {state = {v = (value = 1073741823)}writer_notify = {v = (value = 0)}}poison = {failed = {v = (value = 0)}}data = (value = 1)
}

而是這個state變成了一個很大的值,1073741823,這個值感覺不是巧合,筆者不能理解。

寫鎖是獨占的。

筆者添加4個讀鎖,發現state對應的值變成了4

看來根據這個state的值可以判斷是讀鎖還是寫鎖。具體實現筆者不是很清楚,必然和state有很大的關系。

Channel

看看通道

use std::sync::mpsc::channel;
use std::thread;
fn main() {let (tx, rx) = channel();thread::spawn(move || {let val = String::from("hi");tx.send(val).unwrap();});println!("123")
}

tx?和rx用json表示

{"tx": {"inner": {"flavor": {"0": {"counter": "0x0000020b23389b00"}}}},"rx": {"inner": {"flavor": {"0": {"counter": "0x0000020b23389b00"}}}}
}

可以發現,二者的結構是一模一樣的。最后都指向一個地址。

?意思就顯而易見了,把某個消息傳遞到某個地址,然后再從這個地址中獲取消息

這就是通道嗎?有點意思。

總結

看了看,rust的不同類型的結構

感覺這個結構,無論是什么,好像都可以用json表示。有點意思

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

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

相關文章

uniapp使用ui.request 請求流式輸出

正文&#xff1a; 在現代Web開發中&#xff0c;實時數據流和長時間運行的請求變得越來越常見&#xff0c;尤其是在處理大量數據或進行實時通信時。在這種情況下&#xff0c;uniapp 提供的 ui.request 請求方法可以幫助我們輕松實現流式輸出請求。本文將介紹如何使用 uni.reques…

如何恢復被勒索軟件加密的服務器文件(解密與備份策略)

針對勒索軟件加密文件的恢復和解密策略&#xff0c;結合當前數據安全最佳實踐&#xff0c;整理應對指南如下&#xff1a; 一、文件解密與修復方法 立即隔離設備? 斷開網絡連接并禁用共享功能&#xff0c;防止病毒橫向傳播 通過文件后綴異常&#xff08;如.locked、.wxx&…

JS,ES,TS三者什么區別

Java Script(JS)、ECMAScript(ES)、TypeScript(TS) 的核心區別與關聯的詳細解析,結合技術背景、設計目標及應用場景展開說明: 一、核心定義與關系 JavaScript(JS) 定義:一種動態類型、基于原型的腳本語言,由 Netscape 公司于 1995 年首次開發,用于網頁交互功能。角…

【MapReduce入門】深度解析MapReduce:定義、核心特點、優缺點及適用場景

目錄 1 什么是MapReduce&#xff1f; 2 MapReduce的核心特點 2.1 分布式處理 2.2 容錯機制 3 MapReduce的完整工作流程 4 MapReduce的優缺點分析 4.1 優勢 4.2 局限性 5 MapReduce典型應用場景 5.1 適用場景 5.2 不適用場景 6 MapReduce與其他技術的對比 7 總結 1…

【Redis】分布式鎖的實現

目錄 一、本地鎖存在的問題 二、redis實現分布式鎖原理 三、使用示例 四、鎖誤刪問題 解決思路 獲取鎖和釋放鎖代碼優化 五、鎖釋放的原子性問題 解決思路&#xff08;Lua腳本&#xff09; 使用流程 總結 大家好&#xff0c;我是千語。上期給大家講了使用悲觀鎖來解決…

Unity3D對象池設計與實現詳解

前言 在Unity3D中&#xff0c;對象池&#xff08;Object Pooling&#xff09;是一種優化技術&#xff0c;用于減少頻繁實例化和銷毀對象帶來的性能開銷。以下是對象池的詳細設計和實現步驟&#xff1a; 對惹&#xff0c;這里有一個游戲開發交流小組&#xff0c;希望大家可以點…

[Spring]-組件的生命周期

組件生命周期 認識組件的聲明周期 實驗1 通過Bean指定組件的生命周期 package com.guigu.spring.ioc.bean;Data public class User {private String username;private String password;private Car car;Autowiredpublic void setCar(Car car) {System.out.println("自動…

【golang】網絡數據包捕獲庫 gopacket

詳解 github.com/google/gopacket/pcap 包 github.com/google/gopacket/pcap 是 Go 語言中一個強大的網絡數據包捕獲庫&#xff0c;它是 gopacket 項目的一部分&#xff0c;提供了對 libpcap&#xff08;Linux/Unix&#xff09;和 WinPcap&#xff08;Windows&#xff09;的 G…

RBTree的模擬實現

1&#xff1a;紅黑樹的概念 紅?樹是?棵?叉搜索樹&#xff0c;他的每個結點增加?個存儲位來表?結點的顏?&#xff0c;可以是紅?或者??。通過對任何?條從根到葉?的路徑上各個結點的顏?進?約束&#xff0c;紅?樹確保沒有?條路徑會?其他路徑?出2倍&#xff0c;因…

React 第三十九節 React Router 中的 unstable_usePrompt Hook的詳細用法及案例

React Router 中的 unstable_usePrompt 是一個用于在用戶嘗試離開當前頁面時觸發確認提示的自定義鉤子&#xff0c;常用于防止用戶誤操作導致數據丟失&#xff08;例如未保存的表單&#xff09;。 一、unstable_usePrompt用途 防止意外離開頁面&#xff1a;當用戶在當前頁面有…

OSI 7層模型

OSI 7層模型&#xff1a; 1、物理層&#xff08;光纖等把電腦連接起來的物理手段&#xff09; 2、數據鏈路層&#xff08;以太網&#xff0c;確認0和1電信號的分組方式&#xff0c;負責MAC地址&#xff0c;MAC地址用于在網絡中唯一標示一個網卡&#xff0c;相當于網卡的身份證…

視頻編解碼學習十一之視頻原始數據

一、視頻未編碼前的原始數據是怎樣的&#xff1f; 視頻在未編碼前的原始數據被稱為 原始視頻數據&#xff08;Raw Video Data&#xff09;&#xff0c;主要是按照幀&#xff08;Frame&#xff09;來組織的圖像序列。每一幀本質上就是一張圖片&#xff0c;通常采用某種顏色格式…

Redis學習打卡-Day1-SpringDataRedis、有狀態無狀態

Redis的Java客戶端 Jedis 以 Redis 命令作為方法名稱&#xff0c;學習成本低&#xff0c;簡單實用。Jedis 是線程不安全的&#xff0c;并且頻繁的創建和銷毀連接會有性能損耗&#xff0c;因此推薦使用 Jedis 連接池代替Jedis的直連方式。 lettuce Lettuce是基于Netty實現的&am…

告別靜態配置!Spring Boo動態線程池實戰指南:Nacos+Prometheus全鏈路監控

一、引言 1.1 動態線程池的必要性 傳統線程池的參數&#xff08;如核心線程數、隊列容量&#xff09;通常通過配置文件靜態定義&#xff0c;無法根據業務負載動態調整。例如&#xff0c;在電商大促場景中&#xff0c;流量可能瞬間激增&#xff0c;靜態線程池容易因配置不合理導…

Flask如何讀取配置信息

目錄 一、使用 app.config 讀取配置 二、設置配置的幾種方式 1. 直接設置 2. 從 Python 文件加載 3. 從環境變量加載 4. 從字典加載 5. 從 .env 文件加載&#xff08;推薦開發環境用&#xff09; 三、讀取配置值 四、最佳實踐建議 在 Flask 中讀取配置信息有幾種常見方…

【React中useCallback鉤子詳解】

useCallback 是 React 中的一個性能優化 Hook,用于緩存函數引用,避免在組件重新渲染時重復創建相同的函數,從而減少不必要的子組件渲染或副作用執行。以下是其核心要點: 1. 核心作用 函數記憶化:返回一個記憶化的回調函數,僅在依賴項變化時重新創建函數,否則復用之前的函…

【!!!!終極 Java 中間件實戰課:從 0 到 1 構建億級流量電商系統全鏈路解決方案!!!!保姆級教程---超細】

終極 Java 中間件實戰課:電商系統架構實戰教程 電商系統架構實戰教程1. 系統架構設計1.1 系統模塊劃分1.2 技術選型2. 環境搭建2.1 開發環境準備2.2 基礎設施部署3. 用戶服務開發3.1 創建Maven項目3.2 創建用戶服務模塊3.3 配置文件3.4 實體類與數據庫設計3.5 DAO層實現3.6 Se…

C#異步Task,await,async和Unity同步協程

標題 TaskawaitasyncUnity協程 Task Task是聲明異步任務的必要關鍵字&#xff0c;也可以使用Task<>泛型來定義Task的返回值。 await await是用于等待一個Task結束&#xff0c;否則讓出該線程控制權&#xff0c;讓步給其他線程&#xff0c;直到該Task結束才往下運行。 …

【USRP】在linux下安裝python API調用

UHD 源碼安裝 安裝庫 sudo apt-get install autoconf automake build-essential ccache cmake cpufrequtils doxygen ethtool \ g git inetutils-tools libboost-all-dev libncurses5 libncurses5-dev libusb-1.0-0 libusb-1.0-0-dev \ libusb-dev python3-dev python3-mako …

什么是 NoSQL 數據庫?它與關系型數據庫 (RDBMS) 的主要區別是什么?

我們來詳細分析一下 NoSQL 數據庫與關系型數據庫 (RDBMS) 的主要區別。 什么是 NoSQL 數據庫&#xff1f; NoSQL (通常指 “Not Only SQL” 而不僅僅是 “No SQL”) 是一類數據庫管理系統的總稱。它們的設計目標是解決傳統關系型數據庫 (RDBMS) 在某些場景下的局限性&#xf…