目錄
前言
正文
標量類型
復合類型——元組
?復合類型——數組
函數
&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表示。有點意思