STL庫——string(類函數學習)

? ? ? ? ?

づ?ど

?🎉?歡迎點贊支持🎉

個人主頁:勵志不掉頭發的內向程序員;

專欄主頁:C++語言;


文章目錄

前言

一、STL簡介

二、string類的優點

三、標準庫中的string類

四、string的成員函數

4.1、構造函數

?4.2、析構函數

4.3、賦值重載

4.4、運算符重載

4.5、迭代器(iterator)

4.6、Capacity相關函數

4.6.1 size/length函數

4.6.2、max_size函數

4.6.3、capacity函數

4.6.4、reserve/resize函數

4.6.5、clear函數

4.6.6、empty函數

4.6.7、shrink_to_fit函數

4.7、插入刪除相關函數

4.7.1、push_back函數

4.7.2、append函數

4.7.3、operator+=函數

4.7.4、insert函數

4.7.5、pop_back函數

4.7.6、erase函數

4.7.7、replace函數

4.8、查找函數

4.8.1、find函數

4.8.2、rfind函數

4.8.3、find_first_of函數

4.8.4、find_last_of函數

4.8.5、find_first_not_of/find_last_not_of函數

4.9、其他函數

4.9.1、c_str函數

4.9.2、copy函數

4.9.3、substr函數

五、非成員函數

5.1、operator+函數

5.2、<>函數

5.3、getline函數

總結


前言

本章節我們就來說說我們C++與C語言又一個巨大的區別,那就是STL庫,在這個庫中收錄了我們很多經常使用的數據結構和算法,我們之后的章節會來具體的講解和學習,接下來我們來一起看看吧。


一、STL簡介

STL是C++標準庫的重要組成部分,不僅是一個可復用的組件庫,而且是一個包羅數據結構和算法的軟件框架。

STL的六大組件

二、string類的優點

與C語言相比,我們STL容器中(嚴格來說應該是C++標準庫)引入了我們的string,它的出現幫助我們去管理字符串,這使得我們對字符串的使用更加規范以及更加簡單快捷,出錯率也與自己去實現相比大大的降低了。

三、標準庫中的string類

我們可以看看我們string類中有哪些成員函數,string - C++ Reference

我們可以粗略的看到我們string類的成員變量是很多的,我們為了完全搞懂string類,我們就來一個一個成員函數的學習和模擬實現吧。

四、string的成員函數

我們string類都保存在我們string的頭文件中

#include <string>

4.1、構造函數

我們學習類第一步就應該先去查看它的構造函數

我們string設計時間比STL早,有很多設計沒有參考,所以我們學習時就會覺得它有些設計是十分冗余的,就比如光是string的構造函數就有7種,但是沒有關系,只有string是這樣的,我們只要把經常要用的學會就行,我也只會模擬實現經常要用的成員函數。

#include <string>int main()
{string s1;string s2("11111111");string s3(s2);// 重載了流輸入輸出cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cin >> s1;cout << s1 << endl;return 0;
}

上面3個是我們主要使用的構造函數,接下來講講剩下的幾個。

第3個構造函數是用來構造一個字符串的一部分的。

第一個參數是用那個字符串構造,第二個則是從哪個位置,第三個參數是拷貝多少字符(如果剩下的不夠就有多少拷貝多少)。

#include <string>int main()
{string s1("hello world");string s2(s1, 6, 5);string s3(s1, 6, 100);cout << s2 << endl;cout << s3 << endl;return 0;
}

當然如果我們不傳最后一個參數,那就是默認拷貝到結尾,它的缺省參數是一個npos

它是一個靜態成員變量。我們可以試著突破類域去看看它的值是多少。

#include <string>int main()
{cout << string::npos << endl;return 0;
}

由于我們的字符串不可能有這么長,所以這就可以默認拷貝到最后一個位置了。

第5個構造是用來構造字符串前面一部分的。

第一個參數是用來輸入字符串的,第二個參數則是確定拷貝前面幾個字符,要是字符數目不夠則是全拷貝。

#include <string>int main()
{string s1("hello world", 5);string s2("hello world", 100);cout << s1 << endl;cout << s2 << endl;return 0;
}

第6個構造就是用n個字符c去初始化。

第一個參數就是要幾個字符,第二個參數就是字符是什么。

#include <string>int main()
{string s1(10, 'x');cout << s1 << endl;return 0;
}

還有最后一個暫時不講,之后再說明。

?4.2、析構函數

析構函數沒有什么必要去看,因為它是系統自動調用的,我們無需手動調用。

4.3、賦值重載

第一種就是把一個string賦值給另外一個string。

int main()
{string s1("xxxxxxxxxxxxx");string s2;s2 = s1;cout << s2 << endl;return 0;
}

第二種是把我們的字符串賦值給我們的string。

int main()
{string s1;s1 = "xxxxxxxxxx";cout << s1 << endl;return 0;
}

第三種則是把我們字符賦值給我們string。

int main()
{string s1;s1 = 'X';cout << s1 << endl;return 0;
}

我們一般使用第一種和第二種即可,第三種賦值重載沒有必要,因為一個字符也算字符串,也可以用第二種代替。

4.4、運算符重載

[ ]符重載:

我們string類將[]符進行了重載,這無疑是一個高明的操作,因為這樣就使得我們的字符串和數組一樣可以非常方便的修改和查詢了。

int main()
{string s1("hello world");//修改指定字符s1[3] = '*';s1[5] = '#';cout << s1 << endl;//查看指定字符cout << s1[4] << " " << s1[7] << endl;return 0;
}

同時我們還可以通過[]符來遍歷我們的字符串。

int main()
{string s1("hello world");//size()是string中返回我們字符串大小的函數for (int i = 0; i < s1.size(); i++){cout << s1[i] << " ";}cout << endl;return 0;
}

這樣操作主要是通過我們的運算符通過返回我們類型的引用去修改指定位置的字符來實現的,我們下一章節再來細聊。
除了這種遍歷變量的方式,我們還有兩種,下面會講。

4.5、迭代器(iterator)

我們的迭代器是STL的一大組件,其作用主要就是用來遍歷和訪問我們的容器。我們先來看看它的操作。

int main()
{string s1("hello world");//size()是string中返回我們字符串大小的函數string::iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";++it;}cout << endl;return 0;
}

這樣寫就實現了我們遍歷的效果。我們仔細觀察這些代碼,感覺就很像指針。我們迭代器的實現千變萬化,只要能夠達到我們所需要的效果即可,所以我們也不確定它到底是怎么實現的,可能有的就是用指針實現的。但是我們可以想象成指針。

我們的begin()是返回string空間開始位置的迭代器,而end()是我們返回最后一個有效字符的位置,也就是'\0'的位置的迭代器。

大致就是這個樣子,我們從begin到end,一個一個遍歷過去,如果是指針,那就是一個一個解引用后再++,一直到end后停止,這個很好理解,如果不是指針,那我們就得運算符重載了,把我們'*'、'++'兩個運算符重載成我們和指針那樣的操作了。所以我們的迭代器可能是指針,也可能不是。

iterator給我們STL庫中所有的容器提供了一個通用的遍歷和訪問的方法,讓它們統一起來,這就是迭代器的厲害之處。

當然,我們除了這種正向迭代器,還有反向迭代器

int main()
{string s1("hello world");string::reverse_iterator rit = s1.rbegin();while (rit != s1.rend()){cout << *rit << " ";rit++;}cout << endl;return 0;
}

它的寫法和剛才的正向迭代器很像。

它也是使用++,只不過是倒著走的。我們可以這樣子理解

我們封裝了++后使其倒著運行。

當然,有的時候我們會碰到const string,但是我們的普通迭代器可讀可寫,會導致權限放大不能調用怎么辦呢?這個時候就得用const_iterator迭代器了。用法和iterator是一樣的,只是不能修改,只能遍歷。

int main()
{string s1("hello world");string::const_iterator cit = s1.cbegin();while (cit != s1.cend()){cout << *cit << " ";cit++;}cout << endl;return 0;
}

當然,也有const反向迭代器

int main()
{string s1("hello world");string::const_reverse_iterator crit = s1.crbegin();while (crit != s1.crend()){cout << *crit << " ";crit++;}cout << endl;return 0;
}

用法都是類似的,大家記住就好了,等下一章節講解模擬實現是在來細講這些內容。

我們還有一種遍歷變量的方法,就是范圍for

int main()
{string s1("hello world");for (auto ch : s1){cout << ch << " ";}cout << endl;return 0;
}

這個代碼的含義是我們從我們的s1中去取我們的每一個變量,然后傳給我們的ch(自定義的,叫啥無所謂)中去。

我們再來聊聊auto,它代表的是自動推導類型,它會自動去推導我們s1傳過來的是什么類型的變量,auto就是什么類型的,這里是char,所以auto就是char,當然我們自己寫char也可以。

我們auto的主要作用是來簡化我們的代碼而使用的,例如map<string, string>::iterator可以直接用auto代替,是不是簡單多了。但是它的代價是犧牲了可讀性。

當然我們auto必須要初始化,不然它就不知道它因該推導成什么類型。也不能一行定義不同類型的變量。也不能定義數組。

// 不能這樣寫
auto a;
auto a = 1, b = 1.1;
auto array[] = { 1, 2, 3, 4, 5, 6 };

我們的auto不能做參數,但是可以做返回值,雖然不建議這么做。

我們接著說范圍for,

	for (char ch : s1){cout << ch << " ";}

但是我們這里一般都用auto。范圍for可以自動賦值,自動迭代,自動判斷結束,它的底層其實是迭代器,雖然看上去很厲害,但其實就是迭代器套了一層殼。

同時他不會去改變我們s1的內容,它相當于是傳*it給我們的ch而非it。

int main()
{string s1("hello world");for (auto ch : s1){ch -= 2;cout << ch << " ";}cout << endl;cout << s1;return 0;
}

我們可以看出它是沒有修改s1的。

如果是想要修改得在auto后加&,相當于從之前傳輸過來的char類型變成了char&類型

int main()
{string s1("hello world");for (auto& ch : s1){ch -= 2;cout << ch << " ";}cout << endl;cout << s1;return 0;
}

我們所講的3種遍歷方式在性能方面是沒有任何區別的,可以隨便使用。

4.6、Capacity相關函數

4.6.1 size/length函數

這兩個函數都是用來返回我們的字符串中字符的數量的,使用方法也很簡單

int main()
{string s1("hello world");cout << s1.size() << endl;cout << s1.length() << endl;return 0;
}

它們就是兩個不同名字但是作用完全一樣的函數。我們length不具有通用性,只屬于string容器,但是我們的size是所有容器都有的。

4.6.2、max_size函數

這個函數的作用就是和你說說我們的string最大能開多大,實際就是整型的最大值。沒有什么用處,而且過于理想化,實際上根本開不了這么大。

int main()
{string s1("hello world");cout << s1.max_size() << endl;return 0;
}

4.6.3、capacity函數

返回我們string容量的函數。

int main()
{string s1("hello world");cout << s1.capacity() << endl;return 0;
}

我們可以先來看看我們的string是怎么擴容的

int main()
{string s;// 得到初始內存size_t sz = s.capacity();cout << "capacity changed: " << sz << endl;cout << "make s grow:" << endl;for (int i = 0; i < 100; i++){// 循環插入c去看它擴容s.push_back('c');// 如果擴容了就打印看看新擴容的大小if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << endl;}}
}

我們可以看到,我們第一次是2倍擴容,其他的時候就是1.5倍擴容。這是因為我們vs的工程師為了防止我們總是使用不滿string,為了效率所以在string上增加了一個buffer[16]的字符串,當我們的字符串沒有滿16個字符時我們的編譯器就不會在堆上開辟空間,而是在棧上的buffer的字符串中。

所以我們從第一次擴容是2倍擴容是特殊情況,后面都是1.5倍擴容。當然不同編譯器擴容方式不一樣。

4.6.4、reserve/resize函數

reserve是用來開辟空間的,它能提前開辟好我們指定用到的空間,從而減少擴容次數。

int main()
{string s;s.reserve(100);cout << s.capacity() << endl;return 0;
}

但是其實這個只是讓我們編譯器至少開辟100的空間,具體是多多少得看編譯器操作,因為編譯器會做整數倍對齊。

當然,我們的reserve是一般是不會縮容的,但是還是要看具體的服務器。

int main()
{string s("0123456789");cout << s.capacity() << endl;s.reserve(5);cout << s.capacity() << endl;s.reserve(20);s.reserve(15);cout << s.capacity() << endl;return 0;
}

resize則是可以擴容插入,如果它比size小會刪除數據,如果比size大但是capacity小的話會在后面插入數據,如果你沒給會插入默認字符' \0 ',如果比capacity大則會擴容。

4.6.5、clear函數

這個函數是用來清空我們的字符串的數據,但是一般不會清理容量

int main()
{string s("0123456789");cout << s << endl;s.clear();cout << s << endl;cout << s.capacity() << endl;return 0;
}

4.6.6、empty函數

判斷我們string是不是空的,有沒有字符。

int main()
{string s("0123456789");if (s.empty()) cout << "Yes" << endl;else cout << "No" << endl;s.clear();if (s.empty()) cout << "Yes" << endl;else cout << "No" << endl;return 0;
}

4.6.7、shrink_to_fit函數

這個函數也是用來縮容的,但是和reserve一樣也不一定會成功。

4.7、插入刪除相關函數

4.7.1、push_back函數

這個函數的功能是尾插一個字符,它只能插入一個字符,不能插入字符串,設計的蠻雞肋的。

int main()
{string s("1234");// 如果用雙引號就會報錯,因為不能插入字符串s.push_back('5');cout << s << endl;return 0;
}

4.7.2、append函數

想要插入字符串就可以用append,但是一般我們就使用第三個,別的沒有必要使用,這里簡單介紹一下把

第一個:

單純的在末尾插入一個string字符串。

int main()
{string s1("hello ");string s2("world");s1.append(s2);cout << s1 << endl;return 0;
}

第二個:

在末尾插入字符串str從subpos位置開始的sublen個字符。

int main()
{string s1("hello ");string s2("world");s1.append(s2, 1, 3);cout << s1 << endl;return 0;
}

如果剩余數不足那就取到末尾。

第三個:

直接在后面插入一個字符串。

int main()
{string s1("hello ");s1.append("world");cout << s1 << endl;return 0;
}

第四個:

在末尾插入s前n個字符,如果剩下的不夠,則取到末尾。

int main()
{string s1("hello ");s1.append("world", 3);cout << s1 << endl;return 0;
}

第五個:

就是在末尾插入n給字符c。

第六個后面再將。

4.7.3、operator+=函數

這個是我們string中最常用的尾插用法,它可以兼容字符和字符串,而且可讀性也很好。

int main()
{string s1("hello");string s2("world");s1 += ' ';s1 += s2;s1 += "################";cout << s1 << endl;return 0;
}

4.7.4、insert函數

我們前面就學了尾插,其他位置的插入就用這個函數,這個函數也十分的冗余,主要用的就2個,如果我們要插入我們的字符串,可以用第1種和第3種。

int main()
{string s1("hello");string s2("world");// 第一種方法s1.insert(4, s2);cout << s1 << endl;// 第二種方法s1.insert(0, "########");cout << s1 << endl;return 0;
}

插入字符也可以把字符當字符串,但是如果一定得是字符的話那我們就只能用第五種或者第六種辦法了。

int main()
{string s1("hello");char c = '#';// 第五種方法,在第0位置插入1個字符cs1.insert(0, 1, c);cout << s1 << endl;// 第六種方法s1.insert(s1.end(), c);cout << s1 << endl;return 0;
}

其他的不常用,大家可以自己去試試看看怎么用,很簡單。

4.7.5、pop_back函數

這個就不用多說了,就是尾刪。

4.7.6、erase函數

主要就是使用第1個,在pos位置刪除len個字符,如果沒寫len或者剩下的不足那就在pos后面全刪了。

int main()
{string s1("hello world");s1.erase(2, 2);cout << s1 << endl;return 0;
}

第二個則是迭代器刪除,只能刪除一個,

int main()
{string s1("hello world");s1.erase(s1.begin() + 2);cout << s1 << endl;return 0;
}

第3個則是刪除一個區間的。

4.7.7、replace函數

這個函數的主要作用就是替換,設計的也很麻煩,就講幾個經常使用的,大家要是有需要的再查庫就好了。

int main()
{string s1("hello world");// 第5個位置替換成"%%",替換3個字符s1.replace(5, 3, "%%");cout << s1 << endl;return 0;
}

4.8、查找函數

4.8.1、find函數

我們可以查找一個string字符串,或者一個字符,它如果找到了就會返回第一個匹配位置的字符下標,沒找到就會返回npos。這里面的pos表示從哪里開始找起。

int main()
{string s1("hello world");string s2("wor");size_t pos = s1.find(s2);cout << pos << endl;// 從第7個位置開始找pos = s1.find("s2, 7");cout << pos << endl;pos = s1.find(' ');cout << pos << endl;return 0;
}

4.8.2、rfind函數

rfind和find用法相同,就是rfind是倒著查找的,這里就不多贅述了。返回值就是從后往前第一次出現的下標,如果沒有就返回npos。

4.8.3、find_first_of函數

這個函數的意思不是說找第一個,因為我們find就是第一個,而是說找任意一個,就比如

int main()
{std::string str("Please, replace the vowels in this sentence by asterisks.");std::size_t found = str.find_first_of("abcd");// 一直查找,知道找不到為止while (found != std::string::npos){str[found] = '*';// 從已經找過的位置接著往下找found = str.find_first_of("abcd", found + 1);}std::cout << str << '\n';return 0;
}

我們這個函數就是把我們傳進去的字符串"abcd"中的每一個字符和我們的原文進行配對,如果有其中有其中一個字符可以配對上那就返回第一個配對上的下標,所以上面我們str字符串中的a、b、c、d字符全部替換成了我們的*號。

4.8.4、find_last_of函數

和我們的find_first_of一樣,只不過是反向查找。

4.8.5、find_first_not_of/find_last_not_of函數

分別是find_first_of和find_last_of的對立,就是查找除了我們字符串中的字符其他的字符。

int main()
{std::string str("Please, replace the vowels in this sentence by asterisks.");std::size_t found = str.find_first_not_of("abcd");while (found != std::string::npos){str[found] = '*';found = str.find_first_not_of("abcd", found + 1);}std::cout << str << '\n';return 0;
}

4.9、其他函數

4.9.1、c_str函數

此函數的作用就是返回底層字符串的指針。這個函數的意義就是兼容C語言的。

4.9.2、copy函數

這就是一個拷貝,一般用的很少用,而且我們還要手動的去給它增加' \0 ',不然他就無法檢測到什么時候停下,它的返回值就是拷貝了多少個字符。

int main()
{string s1("hello world");char buffer[10];// 從s1中的第3個字符開始拷貝4個字符size_t len = s1.copy(buffer, 4, 3);// 手動增加\0,不然就會出錯cout << buffer << endl;buffer[len] = '\0';cout << buffer << endl;return 0;
}

4.9.3、substr函數

這個是我們獲取字串最常用的方法。是從pos開始的len個字符,如果不給len就拷貝到結尾。

int main()
{string s1("0123456789");string s2, s3;s2 = s1.substr(4, 7);s3 = s1.substr(5);cout << s2 << endl;cout << s3 << endl;return 0;
}

五、非成員函數

5.1、operator+函數

我們operator+沒有重載成成員函數的原因是為了方便更加自由的操作

int main()
{string s1("hello");// 這個重載成成員函數就可以做到string s2 = s1 + "world";cout << s2 << endl;// 這樣如果是重載函數那就做不到了string s3 = "world" + s1;cout << s3 << endl;return 0;
}

這樣就自由了很多。

5.2、<</>>函數

不多贅述,前往都用了很多次了。

5.3、getline函數

這個函數的作用就是改變我們字符串的分割符,我們的字符串默認是以空格和換行符作為分割,這就使得我們有的時候想要記錄一些句子卻記錄不了,因為有空格。

int main()
{string s1;cin >> s1;cout << s1;return 0;
}

為了避免這種情況,我們就可以用getline來改變分隔符。它的第一個參數是流輸入,一般是cin,第二個參數就是我們要輸入的字符串,第三個參數就是我們想要的分隔符,如果不寫就默認是換行為分隔符。

int main()
{string s1;getline(cin, s1);cout << s1;return 0;
}

以*為分隔符

int main()
{string s1;getline(cin, s1, '*');cout << s1;return 0;
}


總結

以上便是我們string的各種常用函數的使用方法,雖然很多,但是都不是很難,我們也不用死記硬背,我們之后和日常使用會一次又一次的反復記憶,我們如果忘記了再回來或者查文檔去看看就好了,下一章節我們回來試著模擬實現string,下一章節再見。

🎇堅持到這里已經很厲害啦,辛苦啦🎇

? ? ? ? ?

づ?ど

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

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

相關文章

登上Nature!清華大學光學神經網絡研究突破

2025深度學習發論文&模型漲點之——光學神經網絡光學神經網絡的基本原理是利用光的傳播、干涉、衍射等特性來實現神經網絡中的信息處理和計算。在傳統神經網絡中&#xff0c;信息以電信號的形式在電子元件之間傳輸和處理&#xff0c;而在光學神經網絡中&#xff0c;信息則以…

【java】對word文件設置只讀權限

文件流輸出時 template.getXWPFDocument().enforceCommentsProtection(); 文件輸出時 //打開己創建的word文檔 XWPFDocument document new XWPFDocument(new FileInputStream("output.docx")); //設置文檔為只讀 document.enforceReadonlyProtection(); //保存文…

Zookeeper 在 Kafka 中扮演了什么角色?

在 Apache Kafka 的早期架構中&#xff0c;ZooKeeper 扮演了分布式協調服務角色&#xff0c;負責管理和協調整個 Kafka 集群。 盡管新版本的 Kafka 正在逐步移除對 ZooKeeper 的依賴&#xff0c;但在許多現有和較早的系統中&#xff0c;了解 ZooKeeper 的作用仍然非常重要。 Zo…

什么叫做 “可迭代的產品矩陣”?如何落地??

“可迭代的產品矩陣” 不是靜態的產品組合&#xff0c;而是圍繞用戶需求與商業目標構建的動態生態。它以核心產品為根基&#xff0c;通過多維度延伸形成產品網絡&#xff0c;同時具備根據市場反饋持續優化的彈性&#xff0c;讓產品體系既能覆蓋用戶全生命周期需求&#xff0c;又…

Nginx代理配置詳解:正向代理與反向代理完全指南

系列文章索引&#xff1a; 第一篇&#xff1a;《Nginx入門與安裝詳解&#xff1a;從零開始搭建高性能Web服務器》第二篇&#xff1a;《Nginx基礎配置詳解&#xff1a;nginx.conf核心配置與虛擬主機實戰》第三篇&#xff1a;《Nginx代理配置詳解&#xff1a;正向代理與反向代理…

Vue3 Element-plus 封裝Select下拉復選框選擇器

廢話不多說&#xff0c;樣式如下&#xff0c;代碼如下&#xff0c;需要自取<template><el-selectv-model"selectValue"class"checkbox-select"multiple:placeholder"placeholder":style"{ width: width }"change"change…

jenkins 自動部署

一、win10 環境安裝&#xff1a; 1、jdk 下載安裝&#xff1a;Index of openjdk-local 2、配置環境變量&#xff1a; 3、jenkins 下載&#xff1a;Download and deploy 下載后的結果&#xff1a;jenkins.war 4、jenkins 啟動&#xff1a; 5、創建管理員用戶 admin 登錄系統…

2020 GPT3 原文 Language Models are Few-Shot Learners 精選注解

本文為個人閱讀GPT3&#xff0c;部分內容注解&#xff0c;由于GPT3原文篇幅較長&#xff0c;且GPT3無有效開源信息 這里就不再一一粘貼&#xff0c;僅對原文部分內容做注解&#xff0c;僅供參考 詳情參考原文鏈接 原文鏈接&#xff1a;https://arxiv.org/pdf/2005.14165 語言模…

設計模式筆記_行為型_迭代器模式

1. 迭代器模式介紹迭代器模式&#xff08;Iterator Pattern&#xff09;是一種行為設計模式&#xff0c;旨在提供一種方法順序訪問一個聚合對象中的各個元素&#xff0c;而又不需要暴露該對象的內部表示。這個模式的主要目的是將集合的遍歷與集合本身分離&#xff0c;使得用戶可…

【Part 4 未來趨勢與技術展望】第一節|技術上的抉擇:三維實時渲染與VR全景視頻的共生

《VR 360全景視頻開發》專欄 將帶你深入探索從全景視頻制作到Unity眼鏡端應用開發的全流程技術。專欄內容涵蓋安卓原生VR播放器開發、Unity VR視頻渲染與手勢交互、360全景視頻制作與優化&#xff0c;以及高分辨率視頻性能優化等實戰技巧。 &#x1f4dd; 希望通過這個專欄&am…

mac查看nginx安裝位置 mac nginx啟動、重啟、關閉

安裝工具&#xff1a;homebrew步驟&#xff1a;1、打開終端&#xff0c;習慣性命令&#xff1a;brew update //結果&#xff1a;Already up-to-date.2、終端繼續執行命令&#xff1a;brew search nginx //查詢要安裝的軟件是否存在3、執行命令&#xff1a;brew info nginx4. …

網絡通信的基本概念與設備

目錄 一、互聯網 二、JAVA跨平臺與C/C的原理 1、JAVA跨平臺的原理 2、C/C跨平臺的原理 三、網絡互連模型 四、客戶端與服務器 五、計算機之間的通信基礎 1、IP地址與MAC地址 2、ARP與ICMP對比 ①ARP協議&#xff08;地址解析協議&#xff09; ②ICMP協議&#xff08…

云原生俱樂部-k8s知識點歸納(1)

這篇文章主要是講講k8s中的知識點歸納&#xff0c;以幫助理解。雖然平時也做筆記和總結&#xff0c;但是就將內容復制過來不太好&#xff0c;而且我比較喜歡打字。因此知識點歸納總結還是以敘述的口吻來說說&#xff0c;并結合我的理解加以論述。k8s和docker首先講一講docker和…

基于Node.js+Express的電商管理平臺的設計與實現/基于vue的網上購物商城的設計與實現/基于Node.js+Express的在線銷售系統

基于Node.jsExpress的電商管理平臺的設計與實現/基于vue的網上購物商城的設計與實現/基于Node.jsExpress的在線銷售系統

Git 對象存儲:理解底層原理,實現高效排錯與存儲優化

### 探秘 Git 對象存儲&#xff1a;底層原理與優化實踐#### 一、Git 對象存儲的底層原理 Git 采用**內容尋址文件系統**&#xff0c;核心機制如下&#xff1a; 1. **對象類型與存儲** - **Blob 對象**&#xff1a;存儲文件內容&#xff0c;通過 git hash-object 生成唯一 SHA-…

【2025CVPR-目標檢測方向】RaCFormer:通過基于查詢的雷達-相機融合實現高質量的 3D 目標檢測

1. 研究背景與動機? ?問題?:現有雷達-相機融合方法依賴BEV特征融合,但相機圖像到BEV的轉換因深度估計不準確導致特征錯位;雷達BEV特征稀疏,相機BEV特征因深度誤差存在畸變。 ?核心思路?:提出跨視角查詢融合框架,通過對象查詢(object queries)同時采樣圖像視角(原…

【每日一題】Day 7

560.和為K的子數組 題目&#xff1a; 給你一個整數數組 nums 和一個整數 k &#xff0c;請你統計并返回該數組中和為 k 的子數組的個數 。 子數組是數組中元素的連續非空序列。 示例 1&#xff1a; 輸入&#xff1a;nums [1,1,1], k 2 輸出&#xff1a;2 示例 2&#x…

3ds MAX文件/貼圖名稱亂碼?6大根源及解決方案

在3ds MAX渲染階段&#xff0c;文件或貼圖名稱亂碼導致渲染失敗&#xff0c;是困擾眾多用戶的常見難題。其背后原因多樣&#xff0c;精準定位方能高效解決&#xff1a;亂碼核心根源剖析字符編碼沖突 (最常見)非ASCII字符風險&#xff1a; 文件路徑或名稱包含中文、日文、韓文等…

鏈路聚合路由器OpenMPTCProuter源碼編譯與運行

0.前言 前面寫了兩篇關于MPTCP的文章&#xff1a; 《鏈路聚合技術——多路徑傳輸Multipath TCP(MPTCP)快速實踐》《使用MPTCPBBR進行數據傳輸&#xff0c;讓網絡又快又穩》 對MPTCP有了基本的了解與實踐&#xff0c;并在虛擬的網絡拓撲中實現了鏈路帶寬的疊加。 1.OpenMPTC…

AI時代企業轉型指南:用AI降本增效,銷售轉化翻3倍,獲客成本砍一半!

AI時代&#xff0c;大部分企業每天都在問同一個問題&#xff1a;AI到底能幫我做什么&#xff1f;無論你是做電商、做IP、做操盤手&#xff0c;還是傳統企業老板&#xff0c;你都會發現一個現實——AI真正的用途是用來在業務場景里直接降本增效的。對我個人來說&#xff0c;AI已…