diff --git a/README.md b/README.md index 53b3b840..f7583960 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ ## 学习社区 -为了帮助大家更好的学习和交流 Rust,我们建立了一个社区:**Rust语言学习社区**。 +为了帮助大家更好的学习和交流 Rust,我们建立了一个社区:**Rust语言学习社区**( Rust学社 )。 QQ群 1009730433, 欢迎大家加入,一起 happy,一起进步。 diff --git a/assets/bigPicture.js b/assets/bigPicture.js new file mode 100644 index 00000000..c5063bd6 --- /dev/null +++ b/assets/bigPicture.js @@ -0,0 +1 @@ +var BigPicture=function(){var t,n,e,o,i,r,a,c,p,s,l,d,u,f,m,b,g,h,x,v,y,w,_,T,k,M,S,L,E,A,H,z,I,C=[],D={},O="appendChild",N="createElement",V="removeChild";function W(){var n=t.getBoundingClientRect();return"transform:translate3D("+(n.left-(e.clientWidth-n.width)/2)+"px, "+(n.top-(e.clientHeight-n.height)/2)+"px, 0) scale3D("+t.clientWidth/o.clientWidth+", "+t.clientHeight/o.clientHeight+", 0)"}function q(t){var n=A.length-1;if(!u){if(t>0&&E===n||t<0&&!E){if(!I.loop)return j(i,""),void setTimeout(j,9,i,"animation:"+(t>0?"bpl":"bpf")+" .3s;transition:transform .35s");E=t>0?-1:n+1}if([(E=Math.max(0,Math.min(E+t,n)))-1,E,E+1].forEach(function(t){if(t=Math.max(0,Math.min(t,n)),!D[t]){var e=A[t].src,o=document[N]("IMG");o.addEventListener("load",F.bind(null,e)),o.src=e,D[t]=o}}),D[E].complete)return B(t);u=1,j(m,"opacity:.4;"),e[O](m),D[E].onload=function(){y&&B(t)},D[E].onerror=function(){A[E]={error:"Error loading image"},y&&B(t)}}}function B(n){u&&(e[V](m),u=0);var r=A[E];if(r.error)alert(r.error);else{var a=e.querySelector("img:last-of-type");j(i=o=D[E],"animation:"+(n>0?"bpfl":"bpfr")+" .35s;transition:transform .35s"),j(a,"animation:"+(n>0?"bpfol":"bpfor")+" .35s both"),e[O](i),r.el&&(t=r.el)}H.innerHTML=E+1+"/"+A.length,X(A[E].caption),M&&M([i,A[E]])}function P(){var t,n,e=.95*window.innerHeight,o=.95*window.innerWidth,i=I.dimensions||[1920,1080],r=i[0],a=i[1],p=a/r;p>e/o?n=(t=Math.min(a,e))/p:t=(n=Math.min(r,o))*p,c.style.cssText+="width:"+n+"px;height:"+t+"px;"}function G(t){~[1,4].indexOf(o.readyState)?(U(),setTimeout(function(){o.play()},99)):o.error?U(t):f=setTimeout(G,35,t)}function R(n){I.noLoader||(n&&j(m,"top:"+t.offsetTop+"px;left:"+t.offsetLeft+"px;height:"+t.clientHeight+"px;width:"+t.clientWidth+"px"),t.parentElement[n?O:V](m),u=n)}function X(t){t&&(g.innerHTML=t),j(b,"opacity:"+(t?"1;pointer-events:auto":"0"))}function F(t){!~C.indexOf(t)&&C.push(t)}function U(t){if(u&&R(),T&&T(),"string"==typeof t)return $(),I.onError?I.onError():alert("Error: The requested "+t+" could not be loaded.");_&&F(s),o.style.cssText+=W(),j(e,"opacity:1;pointer-events:auto"),k=setTimeout(k,410),v=1,y=!!A,setTimeout(function(){o.style.cssText+="transition:transform .35s;transform:none",h&&setTimeout(X,250,h)},60)}function Y(t){var n=t?t.target:e,i=[b,x,r,a,g,L,S,m];n.blur(),w||~i.indexOf(n)||(o.style.cssText+=W(),j(e,"pointer-events:auto"),setTimeout($,350),clearTimeout(k),v=0,w=1)}function $(){if((o===c?p:o).removeAttribute("src"),document.body[V](e),e[V](o),j(e,""),j(o,""),X(0),y){for(var t=e.querySelectorAll("img"),n=0;n',n}function d(t,n){var e=document[N]("button");return e.className="bp-lr",e.innerHTML='',j(e,n),e.onclick=function(n){n.stopPropagation(),q(t)},e}var f=document[N]("STYLE");f.innerHTML="#bp_caption,#bp_container{bottom:0;left:0;right:0;position:fixed;opacity:0}#bp_container>*,#bp_loader{position:absolute;right:0;z-index:10}#bp_container,#bp_caption,#bp_container svg{pointer-events:none}#bp_container{top:0;z-index:9999;background:rgba(0,0,0,.7);opacity:0;transition:opacity .35s}#bp_loader{top:0;left:0;bottom:0;display:flex;align-items:center;cursor:wait;background:0;z-index:9}#bp_loader svg{width:50%;max-width:300px;max-height:50%;margin:auto;animation:bpturn 1s infinite linear}#bp_aud,#bp_container img,#bp_sv,#bp_vid{user-select:none;max-height:96%;max-width:96%;top:0;bottom:0;left:0;margin:auto;box-shadow:0 0 3em rgba(0,0,0,.4);z-index:-1}#bp_sv{background:#111}#bp_sv svg{width:66px}#bp_caption{font-size:.9em;padding:1.3em;background:rgba(15,15,15,.94);color:#fff;text-align:center;transition:opacity .3s}#bp_aud{width:650px;top:calc(50% - 20px);bottom:auto;box-shadow:none}#bp_count{left:0;right:auto;padding:14px;color:rgba(255,255,255,.7);font-size:22px;cursor:default}#bp_container button{position:absolute;border:0;outline:0;background:0;cursor:pointer;transition:all .1s}#bp_container>.bp-x{padding:0;height:41px;width:41px;border-radius:100%;top:8px;right:14px;opacity:.8;line-height:1}#bp_container>.bp-x:focus,#bp_container>.bp-x:hover{background:rgba(255,255,255,.2)}.bp-x svg,.bp-xc svg{height:21px;width:20px;fill:#fff;vertical-align:top;}.bp-xc svg{width:16px}#bp_container .bp-xc{left:2%;bottom:100%;padding:9px 20px 7px;background:#d04444;border-radius:2px 2px 0 0;opacity:.85}#bp_container .bp-xc:focus,#bp_container .bp-xc:hover{opacity:1}.bp-lr{top:50%;top:calc(50% - 130px);padding:99px 0;width:6%;background:0;border:0;opacity:.4;transition:opacity .1s}.bp-lr:focus,.bp-lr:hover{opacity:.8}@keyframes bpf{50%{transform:translatex(15px)}100%{transform:none}}@keyframes bpl{50%{transform:translatex(-15px)}100%{transform:none}}@keyframes bpfl{0%{opacity:0;transform:translatex(70px)}100%{opacity:1;transform:none}}@keyframes bpfr{0%{opacity:0;transform:translatex(-70px)}100%{opacity:1;transform:none}}@keyframes bpfol{0%{opacity:1;transform:none}100%{opacity:0;transform:translatex(-70px)}}@keyframes bpfor{0%{opacity:1;transform:none}100%{opacity:0;transform:translatex(70px)}}@keyframes bpturn{0%{transform:none}100%{transform:rotate(360deg)}}@media (max-width:600px){.bp-lr{font-size:15vw}}",document.head[O](f),(e=document[N]("DIV")).id="bp_container",e.onclick=Y,l=s("bp-x"),e[O](l),"ontouchstart"in window&&(z=1,e.ontouchstart=function(n){var e=n.changedTouches;t=e[0].pageX},e.ontouchmove=function(t){t.preventDefault()},e.ontouchend=function(n){var e=n.changedTouches;if(y){var o=e[0].pageX-t;o<-30&&q(1),o>30&&q(-1)}}),i=document[N]("IMG"),(r=document[N]("VIDEO")).id="bp_vid",r.setAttribute("playsinline",1),r.controls=1,r.loop=1,(a=document[N]("audio")).id="bp_aud",a.controls=1,a.loop=1,(H=document[N]("span")).id="bp_count",(b=document[N]("DIV")).id="bp_caption",(x=s("bp-xc")).onclick=X.bind(null,0),b[O](x),g=document[N]("SPAN"),b[O](g),e[O](b),S=d(1,"transform:scalex(-1)"),L=d(-1,"left:0;right:auto"),(m=document[N]("DIV")).id="bp_loader",m.innerHTML='',(c=document[N]("DIV")).id="bp_sv",(p=document[N]("IFRAME")).setAttribute("allowfullscreen",1),p.allow="autoplay; fullscreen",p.onload=function(){return c[V](m)},j(p,"border:0;position:absolute;height:100%;width:100%;left:0;top:0"),c[O](p),i.onload=U,i.onerror=U.bind(null,"image"),window.addEventListener("resize",function(){y||u&&R(1),o===c&&P()}),document.addEventListener("keyup",function(t){var n=t.keyCode;27===n&&v&&Y(),y&&(39===n&&q(1),37===n&&q(-1),38===n&&q(10),40===n&&q(-10))}),document.addEventListener("keydown",function(t){y&&~[37,38,39,40].indexOf(t.keyCode)&&t.preventDefault()}),document.addEventListener("focus",function(t){v&&!e.contains(t.target)&&(t.stopPropagation(),l.focus())},1),n=1}(),u&&(clearTimeout(f),$()),I=w,d=w.ytSrc||w.vimeoSrc,T=w.animationStart,k=w.animationEnd,M=w.onChangeImage,_=0,h=(t=w.el).getAttribute("data-caption"),w.gallery?function(n,r){var a=I.galleryAttribute||"data-bp";if(Array.isArray(n))A=n,h=n[E=r||0].caption;else{var c=(A=[].slice.call("string"==typeof n?document.querySelectorAll(n+" ["+a+"]"):n)).indexOf(t);E=0===r||r?r:-1!==c?c:0,A=A.map(function(t){return{el:t,src:t.getAttribute(a),caption:t.getAttribute("data-caption")}})}_=1,!~C.indexOf(s=A[E].src)&&R(1),A.length>1?(e[O](H),H.innerHTML=E+1+"/"+A.length,z||(e[O](S),e[O](L))):A=0,(o=i).src=s}(w.gallery,w.position):d||w.iframeSrc?(o=c,I.ytSrc?W="https://www.youtube.com/embed/"+d+"?html5=1&rel=0&playsinline=1&autoplay=1":I.vimeoSrc?W="https://player.vimeo.com/video/"+d+"?autoplay=1":I.iframeSrc&&(W=I.iframeSrc),j(m,""),c[O](m),p.src=W,P(),setTimeout(U,9)):w.imgSrc?(_=1,!~C.indexOf(s=w.imgSrc)&&R(1),(o=i).src=s):w.audio?(R(1),(o=a).src=w.audio,G("audio file")):w.vidSrc?(R(1),w.dimensions&&j(r,"width:"+w.dimensions[0]+"px"),D=w.vidSrc,Array.isArray(D)?(o=r.cloneNode(),D.forEach(function(t){var n=document[N]("SOURCE");n.src=t,n.type="video/"+t.match(/.(\w+)$/)[1],o[O](n)})):(o=r).src=D,G("video")):(o=i).src="IMG"===t.tagName?t.src:window.getComputedStyle(t).backgroundImage.replace(/^url|[(|)|'|"]/g,""),e[O](o),document.body[O](e),{close:Y,next:function(){return q(1)},prev:function(){return q(-1)}};var W}}(); \ No newline at end of file diff --git a/assets/custom0.js b/assets/custom0.js new file mode 100644 index 00000000..f2b02840 --- /dev/null +++ b/assets/custom0.js @@ -0,0 +1,104 @@ +(function() { + var path = window.location.pathname; + if (path.endsWith("/print.html")) { + return; + } + + var images = document.querySelectorAll("main img") + Array.prototype.forEach.call(images, function(img) { + img.addEventListener("click", function() { + BigPicture({ + el: img, + }); + }); + }); + + // Un-active everything when you click it + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { + el.addEventHandler("click", function() { + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { + el.classList.remove("active"); + }); + el.classList.add("active"); + }); + }); + + var updateFunction = function() { + + var id; + var elements = document.getElementsByClassName("header"); + Array.prototype.forEach.call(elements, function(el) { + if (window.pageYOffset >= el.offsetTop) { + id = el; + } + }); + + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { + el.classList.remove("active"); + }); + + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { + if (id.href.localeCompare(el.href) == 0) { + el.classList.add("active"); + } + }); + }; + + // Populate sidebar on load + window.addEventListener('load', function() { + var pagetoc = document.getElementsByClassName("pagetoc")[0]; + var elements = document.getElementsByClassName("header"); + Array.prototype.forEach.call(elements, function(el) { + var link = document.createElement("a"); + + // Indent shows hierarchy + var indent = ""; + switch (el.parentElement.tagName) { + case "H1": + return; + // case "H2": + // indent = "20px"; + // break; + case "H3": + indent = "20px"; + break; + case "H4": + indent = "40px"; + break; + default: + break; + } + + link.appendChild(document.createTextNode(el.text)); + link.style.paddingLeft = indent; + link.href = el.href; + pagetoc.appendChild(link); + }); + updateFunction.call(); + }); + + // Handle active elements on scroll + window.addEventListener("scroll", updateFunction); + + var p = path.replace("index.html", ""); + p = p.replace(".html", ""); + var strs = p.split("/"); + if (strs[strs.length-1] == ""){ + strs.pop() + } + var str = strs[strs.length-1]; + var title = document.querySelector("main>h1,h2>a").textContent + var gitalk = new Gitalk({ + clientID: '07ea0357feefeb9de502', + clientSecret: '2f362f6990633ad63f7455b06fc00f4e45c5847d', + repo: 'rust-course-comments', + owner: 'sunface', + admin: ["sunface"], + labels: ['comments'], + title: title, + createIssueManually: false, + id: str, + distractionFreeMode: true + }); + gitalk.render('gitalk-container'); +})(); \ No newline at end of file diff --git a/assets/ferris.css b/assets/ferris.css deleted file mode 100644 index b856d477..00000000 --- a/assets/ferris.css +++ /dev/null @@ -1,33 +0,0 @@ -body.light .does_not_compile, -body.light .panics, -body.light .not_desired_behavior, -body.rust .does_not_compile, -body.rust .panics, -body.rust .not_desired_behavior { - background: #fff1f1; -} - -body.coal .does_not_compile, -body.coal .panics, -body.coal .not_desired_behavior, -body.navy .does_not_compile, -body.navy .panics, -body.navy .not_desired_behavior, -body.ayu .does_not_compile, -body.ayu .panics, -body.ayu .not_desired_behavior { - background: #501f21; -} - -.ferris { - position: absolute; - z-index: 99; - right: 5px; - top: 30px; - width: 10%; - height: auto; -} - -.ferris-explain { - width: 100px; -} \ No newline at end of file diff --git a/assets/ferris.js b/assets/ferris.js deleted file mode 100644 index 06a40cd7..00000000 --- a/assets/ferris.js +++ /dev/null @@ -1,51 +0,0 @@ -var ferrisTypes = [ - { - attr: 'does_not_compile', - title: 'This code does not compile!' - }, - { - attr: 'panics', - title: 'This code panics!' - }, - { - attr: 'unsafe', - title: 'This code block contains unsafe code.' - }, - { - attr: 'not_desired_behavior', - title: 'This code does not produce the desired behavior.' - } -] - -document.addEventListener('DOMContentLoaded', () => { - for (var ferrisType of ferrisTypes) { - attachFerrises(ferrisType) - } -}) - -function attachFerrises (type) { - var elements = document.getElementsByClassName(type.attr) - - for (var codeBlock of elements) { - var lines = codeBlock.textContent.split(/\r|\r\n|\n/).length - 1; - - if (lines >= 4) { - attachFerris(codeBlock, type) - } - } -} - -function attachFerris (element, type) { - var a = document.createElement('a') - a.setAttribute('href', 'ch00-00-introduction.html#ferris') - a.setAttribute('target', '_blank') - - var img = document.createElement('img') - img.setAttribute('src', '/img/ferris/' + type.attr + '.svg') - img.setAttribute('title', type.title) - img.className = 'ferris' - - a.appendChild(img) - - element.parentElement.insertBefore(a, element) -} \ No newline at end of file diff --git a/assets/theme/2018-edition.css b/assets/theme/2018-edition.css deleted file mode 100644 index b1dcf936..00000000 --- a/assets/theme/2018-edition.css +++ /dev/null @@ -1,9 +0,0 @@ -span.caption { - font-size: .8em; - font-weight: 600; -} - -span.caption code { - font-size: 0.875em; - font-weight: 400; -} diff --git a/book.toml b/book.toml index 246e69a4..b72ba694 100644 --- a/book.toml +++ b/book.toml @@ -5,8 +5,8 @@ title = "Rust语言圣经(Rust教程 Rust Course)" src = "src" [output.html] -additional-css = ["assets/ferris.css", "assets/theme/2018-edition.css"] -additional-js = ["assets/ferris.js"] +additional-css = ["theme/style2.css"] +additional-js = ["assets/custom0.js", "assets/bigPicture.js"] git-repository-url = "https://github.com/sunface/rust-course" edit-url-template = "https://github.com/sunface/rust-course/edit/main/{path}" diff --git a/src/SUMMARY.md b/src/SUMMARY.md index b3aea018..cd52cb72 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -217,6 +217,7 @@ - [数据布局](too-many-lists/unsafe-queue/layout.md) - [基本操作](too-many-lists/unsafe-queue/basics.md) - [Miri](too-many-lists/unsafe-queue/miri.md) + - [栈借用](too-many-lists/unsafe-queue/stacked-borrow.md) - [Rust 性能优化 todo](profiling/intro.md) - [深入内存 todo](profiling/memory/intro.md) - [指针和引用 todo](profiling/memory/pointer-ref.md) diff --git a/src/advance/errors.md b/src/advance/errors.md index 4d67e2d8..7716f104 100644 --- a/src/advance/errors.md +++ b/src/advance/errors.md @@ -513,7 +513,7 @@ fn render() -> Result { 上面的代码会报错,原因在于 `render` 函数中的两个 `?` 返回的实际上是不同的错误:`env::var()` 返回的是 `std::env::VarError`,而 `read_to_string` 返回的是 `std::io::Error`。 -为了满足 `render` 函数的签名,我们就需要将 `env::VarError` 和 `io::Error` 归一化为同一种错误类型。要实现这个目的有两种方式: +为了满足 `render` 函数的签名,我们就需要将 `env::VarError` 和 `io::Error` 归一化为同一种错误类型。要实现这个目的有三种方式: - 使用特征对象 `Box` - 自定义错误类型 diff --git a/src/advance/lifetime/advance.md b/src/advance/lifetime/advance.md index 014fdf5c..86bfeabd 100644 --- a/src/advance/lifetime/advance.md +++ b/src/advance/lifetime/advance.md @@ -77,6 +77,8 @@ fn main() { 这就解释了可变借用为啥会在 `main` 函数作用域内有效,最终导致 `foo.share()` 无法再进行不可变借用。 +总结下:`&mut self` 借用的生命周期和 `loan` 的生命周期相同,将持续到 `println` 结束。而在此期间 `foo.share()` 又进行了一次不可变 `&foo` 借用,违背了可变借用与不可变借用不能同时存在的规则,最终导致了编译错误。 + 上述代码实际上完全是正确的,但是因为生命周期系统的“粗糙实现”,导致了编译错误,目前来说,遇到这种生命周期系统不够聪明导致的编译错误,我们也没有太好的办法,只能修改代码去满足它的需求,并期待以后它会更聪明。 #### 例子 2 diff --git a/src/basic/crate-module/use.md b/src/basic/crate-module/use.md index 8430fdfd..05b116d0 100644 --- a/src/basic/crate-module/use.md +++ b/src/basic/crate-module/use.md @@ -143,7 +143,7 @@ pub fn eat_at_restaurant() { ## 使用第三方包 -之前我们一直在引入标准库模块或者自定义模块,现在来引入下第三方包中的模块,关于如何引入外部依赖,我们在 [Cargo 入门](../../first-try/cargo.md#package配置段落)中就有讲,这里直接给出操作步骤: +之前我们一直在引入标准库模块或者自定义模块,现在来引入下第三方包中的模块,关于如何引入外部依赖,我们在 [Cargo 入门](https://course.rs/first-try/cargo.html#package-配置段落)中就有讲,这里直接给出操作步骤: 1. 修改 `Cargo.toml` 文件,在 `[dependencies]` 区域添加一行:`rand = "0.8.3"` 2. 此时,如果你用的是 `VSCode` 和 `rust-analyzer` 插件,该插件会自动拉取该库,你可能需要等它完成后,再进行下一步(VSCode 左下角有提示) diff --git a/src/index-list.md b/src/index-list.md index b2fd9b56..7bec79db 100644 --- a/src/index-list.md +++ b/src/index-list.md @@ -10,10 +10,11 @@ -| NN | NN | NN | NN | NN | NN | NN | NN | NN | NN | NN | NN | NN | NN | -| :---------: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | -| [Sym](#Sym) | [A](#A) | [B](#B) | [C](#C) | [D](#D) | [E](#E) | [F](#F) | [G](#G) | [H](#H) | [I](#I) | [J](#J) | [K](#K) | [L](#L) | [M](#M) | -| [N](#N) | [O](#O) | [P](#P) | [Q](#Q) | [R](#R) | [S](#S) | [T](#T) | [U](#U) | [V](#V) | [W](#W) | [X](#X) | [Y](#Y) | [Z](#Z) | +| NN | NN | NN | NN | NN | NN | NN | NN | NN | NN | NN | +| :---------: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | +| [Sym](#Sym) | [A](#A) | [B](#B) | [C](#C) | [D](#D) | [E](#E) | [F](#F) | [G](#G) | [H](#H) | [I](#I) | [J](#J) | +| [K](#K) | [L](#L) | [M](#M) | [N](#N) | [O](#O) | [P](#P) | [Q](#Q) | [R](#R) | [S](#S) | [T](#T) | [U](#U) | +| [V](#V) | [W](#W) | [X](#X) | [Y](#Y) | [Z](#Z) | ## Sym @@ -45,25 +46,27 @@ ## B -| 名称 | 关键字 | 简介 | -| ---------- | --------- | -------------------------------------- | -| [变量遮蔽] | shadowing | 允许声明相同的变量名,后者会遮蔽掉前者 | -| [布尔] | bool | `true` `false`,占用 1 字节 | -| B | KWB | BIntroduction | +| 名称 | 关键字 | 简介 | +| ----------- | --------- | -------------------------------------- | +| [变量遮蔽] | shadowing | 允许声明相同的变量名,后者会遮蔽掉前者 | +| [bool 布尔] | 布尔类型 | `true` `false`,占用 1 字节 | +| B | KWB | BIntroduction | [变量遮蔽]: https://course.rs/basic/variable.html#变量遮蔽shadowing -[布尔]: https://course.rs/basic/base-type/char-bool.html#布尔bool +[bool 布尔]: https://course.rs/basic/base-type/char-bool.html#布尔bool [back](#head) ## C -| 名称 | 关键字 | 简介 | -| ------ | ------ | -------------------------------- | -| [常量] | const | const MAX_POINTS: u32 = 100_000; | -| C | KWC | CIntroduction | +| 名称 | 关键字 | 简介 | +| ------------ | -------- | --------------------------------- | +| [const 常量] | constant | const MAX_POINTS: u32 = 100_000; | +| [char 字符] | 字符类型 | 使用 `''` 表示,所有的 Unicode 值 | +| C | KWC | CIntroduction | -[常量]: https://course.rs/basic/variable.html#变量和常量之间的差异 +[const 常量]: https://course.rs/basic/variable.html#变量和常量之间的差异 +[char 字符]: https://course.rs/basic/base-type/char-bool.html#字符类型char [back](#head) @@ -189,22 +192,20 @@ ## R -| 名称 | 关键字 | 简介 | -| ---- | ------ | ------------- | -| R | KWR | RIntroduction | +| 名称 | 关键字 | 简介 | +| ------------ | ------ | ---------------------------------------------------------------------------------- | +| [Range 序列] | | 生成连续的数值
只允许用于数字或字符类型
`..` 右半开区间
`..=` 闭合区间 | +| R | KWR | RIntroduction | + +[range 序列]: https://course.rs/basic/base-type/numbers.html#序列range [back](#head) ## S -| 名称 | 关键字 | 简介 | -| ------------ | -------- | ------------------------------------------------------------------------------------------------------ | -| [整数] | 数值类型 | 有符号整数,`i8`,`i16`,`i32`,`i64`,`i128`,`isize`
无符号整数,`u8`,`u16`,`u32`,`u64`,`u128`,`usize` | -| [整形字面量] | 进制书写 | 十进制 `98_222`
十六进制 `0xff`
八进制 `0o77`
二进制 `0b1111_0000`
字节(仅限于`u8`) `b'A'` | -| S | KWS | SIntroduction | - -[整数]: https://course.rs/basic/base-type/numbers.html#整数类型 -[整形字面量]: https://course.rs/basic/base-type/numbers.html#整数类型 +| 名称 | 关键字 | 简介 | +| ---- | ------ | ------------- | +| S | KWS | SIntroduction | [back](#head) @@ -242,12 +243,9 @@ ## X -| 名称 | 关键字 | 简介 | -| ------ | ------ | ---------------------------------------------------------------------------------- | -| [序列] | Range | 生成连续的数值
只允许用于数字或字符类型
`..` 右半开区间
`..=` 闭合区间 | -| X | KWX | XIntroduction | - -[序列]: https://course.rs/basic/base-type/numbers.html#序列range +| 名称 | 关键字 | 简介 | +| ---- | ------ | ------------- | +| X | KWX | XIntroduction | [back](#head) @@ -261,11 +259,13 @@ ## Z -| 名称 | 关键字 | 简介 | -| ---------- | ------ | --------------------------------- | -| [字符类型] | char | 使用 `''` 表示,所有的 Unicode 值 | -| Z | KWZ | ZIntroduction | +| 名称 | 关键字 | 简介 | +| ------------ | -------- | ------------------------------------------------------------------------------------------------------ | +| [整数] | 数值类型 | 有符号整数,`i8`,`i16`,`i32`,`i64`,`i128`,`isize`
无符号整数,`u8`,`u16`,`u32`,`u64`,`u128`,`usize` | +| [整形字面量] | 进制书写 | 十进制 `98_222`
十六进制 `0xff`
八进制 `0o77`
二进制 `0b1111_0000`
字节(仅限于`u8`) `b'A'` | +| Z | KWZ | ZIntroduction | -[字符类型]: https://course.rs/basic/base-type/char-bool.html#字符类型char +[整数]: https://course.rs/basic/base-type/numbers.html#整数类型 +[整形字面量]: https://course.rs/basic/base-type/numbers.html#整数类型 [back](#head) diff --git a/src/too-many-lists/unsafe-queue/stacked-borrow.md b/src/too-many-lists/unsafe-queue/stacked-borrow.md new file mode 100644 index 00000000..94f8c7f4 --- /dev/null +++ b/src/too-many-lists/unsafe-queue/stacked-borrow.md @@ -0,0 +1,111 @@ +# 栈借用( Stacked Borrorw) +上一章节中我们运行 miri 时遇到了一个栈借用错误,还给了文档链接,但这些文档主要是给编译器开发者和 Rust 研究者看的,因此就不进行讲解了。 + +而这里,我们将从一个更高层次的角度来看看何为栈借用。 + +> 目前栈借用在 Rust 语义模型中还是试验阶段,因此破坏这些规则不一定说明你的程序错了。但是除非你在做编译器开发,否则最好还是修复这些错误。事前的麻烦总比事后的不安全要好,特别是当涉及到 UB 未定义行为时 + +## 指针混叠( Pointer Aliasing ) +在开始了解我们破坏的规则之前,首先应该了解为何会有这些规则的存在。这里有多个动机,但是我认为最重要的动机是: 指针混叠. + +当两个指针指向的内存区域存在重叠时,就说这两个指针发生了混叠,这种情况会造成一些问题。例如,编译器使用指针混叠的信息来优化内存的访问,当这些信息出错时,那程序就会被不正确地编译,然后产生一些奇怪的结果。 + +> 实际上,混叠更多关心的是内存访问而不是指针本身,而且只有在其中一个访问是可变的时,才可能出问题。之所以说指针,是因为指针这个概念更方便跟一些规则进行关联。 + +再比如,编译器需要获取一个值时,是该去缓存中查询还是每次都去内存中加载呢?关于这个选择,编译器需要清晰地知道是否有一个指针在背后修改内存,如果内存值被修改了,那缓存显然就失效了。 + +## 安全地栈借用 +有了之前的铺垫,大家肯定希望编译器能对指针混叠的信息了若指掌,但是可以吗?对于 Rust 正常代码而言,这种情况是可以避免的,因为严格的借用规则是我们的后盾:要么同时存在一个可变引用,要么同时存在多个不可变引用,这种规则简直完美避免了:两个指针指向同一块儿重叠内存区域,而其中一个是可变指针。 + +然而实际使用中,有一些情况会较为复杂,例如以下代码中发生了可变引用的再借用( reborrow ): +```rust +let mut data = 10; +let ref1 = &mut data; +let ref2 = &mut *ref1; + +*ref2 += 2; +*ref1 += 1; + +println!("{}", data); +``` + +看上去像是违反了借用规则,但是这段代码确实可以正常编译运行,如果交换下引用使用的顺序呢? +```rust +let mut data = 10; +let ref1 = &mut data; +let ref2 = &mut *ref1; + +// ORDER SWAPPED! +*ref1 += 1; +*ref2 += 2; + +println!("{}", data); +``` + +```shell +error[E0503]: cannot use `*ref1` because it was mutably borrowed + --> src/main.rs:6:5 + | +4 | let ref2 = &mut *ref1; + | ---------- borrow of `*ref1` occurs here +5 | +6 | *ref1 += 1; + | ^^^^^^^^^^ use of borrowed `*ref1` +7 | *ref2 += 2; + | ---------- borrow later used here + +For more information about this error, try `rustc --explain E0503`. +error: could not compile `playground` due to previous error +``` + +果不其然,编译器抛出了错误,当我们再借用了一个可变引用时,那原始的引用就不能再被使用,直到借用者完成了任务:借用者的借用有效范围并不是看作用域,而是看最后一次使用的位置,正因为如此,第一段代码可以编译通过,而第二段不行,这是著名的生命周期 [NLL 规则](https://course.rs/advance/lifetime/advance.html#nll-non-lexical-lifetime)。 + +以上就是我们拥有再借用但是还拥有混叠信息的原因:所有的再借用都在清晰地进行嵌套,因此每个再借用都不会与其它的冲突。那大家知道什么方法可以很好的展现嵌套的事物吗?答案就是使用栈来存放这些嵌套的借用。 + +嘿,这不就是栈借用吗? + +这个栈的顶部借用就是当前正在使用( live )的借用,而它清晰的知道在它使用的期间不会发生混叠。当对一个指针进行再借用时,新的借用会被插入到栈的顶部,并变成 live 状态。如果要将一个旧的指针变成 live,就需要将借用栈上在它之前的借用全部弹出( pop )。 + +通过栈借用的方式,我们保证了尽管存在多个再借用,但是在同一个时间,只会有一个可变引用访问目标内存,再也不用担心指针混叠的问题了。只要不去访问一个已经被弹出借用栈的指针,就会非常安全! + +从表述方式来说,与其说使用 `ref1` 会让 `ref2` 不合法,不如说 `ref2` 必须要在所有使用情况下合法,`ref1` 恰恰是其中一种情况,会破坏 `ref2` 的合法性。而编译器的报错也是选择了第二种表述方式:无法使用 `*ref1`,原因是它已经被可变借用了,可以看出,第二种表述方式比第一种要更加符合直觉。 + +**但是,当使用 `unsafe` 指针时,借用检查器就无法再帮助我们了!** + +## 不安全地栈借用 +所以,我们现在需要一个方式让 unsafe 指针也可以参与到栈借用系统中来,即使编译器无法正确地跟踪它们。同时我们也希望这个系统能宽松一些,不要很容易就产生 UB。 + +这是一个困难的问题,我也不知道该如何解决,但是目前在编写栈借用系统的开发者显然是有想法的,例如 miri 就是其中一个产物。 + +从一个高抽象层次来看,当我们将一个引用转换成裸指针时,就是一种再借用。那么随后,裸指针就可以对目标内存进行操作,当再借用结束时,发生的事情跟正常的再借用结束也没有区别。 + +但是问题是,你还可以将一个裸指针转变成引用,最重要的是,还可以对裸指针进行拷贝!如果发生了以下转换 `&mut -> *mut -> &mut -> *mut`,然后去访问第一个 `*mut`,这种见鬼的情况下,栈借用该如何发挥作用? + +反正我不知道,只能求助于 miri 了。事实上,正因为这种情况,miri 还提供了试验性的模式: `-Zmiri-tag-raw-pointers`。可以通过环境的方式来开启该模式: +```shell +MIRIFLAGS="-Zmiri-tag-raw-pointers" cargo +nightly-2022-01-21 miri test +``` + +如果是 Windows,你需要设置全局变量: +```shell +$env:MIRIFLAGS="-Zmiri-tag-raw-pointers" +cargo +nightly-2022-01-21 miri test +``` + +## 管理栈借用 +因为之前的问题,使用裸指针,应该遵守一个原则:**一旦开始使用裸指针,就要尝试着只使用它**。 + +现在,我们依然希望在接口中使用安全的引用去构建一个安全的抽象,例如在函数参数中使用引用而不是裸指针,这样我们的用户就无需操心 unsafe 的问题。 + +为此,我们需要做以下事情: + +1. 在开始时,将输入参数中的引用转换成裸指针 +2. 在函数体中只使用裸指针 +3. 返回之前,将裸指针转换成安全的指针 + +但是由于数据结构中的字段都是私有的,无需暴露给用户,因此无需这么麻烦,直接使用裸指针即可。 + +事实上,一个依然存在的问题就是还在继续使用 `Box`, 它会告诉编译器:hey,这个看上去很像是 `&mut` ,因为它唯一的持有那个指针。 + +但是我们在链表中一直使用的裸指针是指向 Box 的内部,所以无论何时我们通过正常的方式访问 Box,我们都有可能让该裸指针的再借用变得不合法。 + diff --git a/theme/index.hbs b/theme/index.hbs new file mode 100644 index 00000000..69134bae --- /dev/null +++ b/theme/index.hbs @@ -0,0 +1,318 @@ + + + + + + {{ title }} + {{#if is_print }} + + {{/if}} + {{#if base_url}} + + {{/if}} + + + + {{> head}} + + + + + + + {{#if favicon_svg}} + + {{/if}} + {{#if favicon_png}} + + {{/if}} + + + + {{#if print_enable}} + + {{/if}} + + + + {{#if copy_fonts}} + + {{/if}} + + + + + + + + {{#each additional_css}} + + {{/each}} + + {{#if mathjax_support}} + + + {{/if}} + + + + + + + + + + + + + + + + + + + +
+ +
+ {{> header}} + + + + {{#if search_enabled}} + + {{/if}} + + + + +
+ +
+
+ {{{ content }}} +
+
+ + +
+
+ + + +
+ + {{#if livereload}} + + + {{/if}} + + {{#if google_analytics}} + + + {{/if}} + + {{#if playground_line_numbers}} + + {{/if}} + + {{#if playground_copyable}} + + {{/if}} + + {{#if playground_js}} + + + + + + {{/if}} + + {{#if search_js}} + + + + {{/if}} + + + + + + + {{#each additional_js}} + + {{/each}} + + {{#if is_print}} + {{#if mathjax_support}} + + {{else}} + + {{/if}} + {{/if}} + + + \ No newline at end of file diff --git a/theme/style2.css b/theme/style2.css new file mode 100644 index 00000000..933d2dba --- /dev/null +++ b/theme/style2.css @@ -0,0 +1,53 @@ +@media only screen and (max-width:1080px) { + .sidetoc { + display: none !important; + } +} + +@media only screen and (min-width:1080px) { + main { + position: relative; + padding-right: 170px !important; + } + .sidetoc { + margin-left: auto; + margin-right: auto; + /*left: calc(100% + (var(--content-max-width))/4 - 180px);*/ + left: calc(100% - 200px); + position: absolute; + } + .pagetoc { + position: fixed; + width: 200px; + height: calc(100vh - var(--menu-bar-height) - 0.67em * 4); + overflow: auto; + } + .pagetoc a { + border-left: 1px solid var(--sidebar-bg); + color: var(--fg) !important; + display: block; + padding-bottom: 5px; + padding-top: 5px; + padding-left: 10px; + text-align: left; + text-decoration: none; + font-size: 1.2rem; + } + .pagetoc a:hover, + .pagetoc a.active { + background: var(--sidebar-bg); + color: var(--sidebar-fg) !important; + } + .pagetoc .active { + background: var(--sidebar-bg); + color: var(--sidebar-fg); + } +} + +.page-footer { + margin-top: 50px; + border-top: 1px solid #ccc; + overflow: hidden; + padding: 10px 0; + color: gray; +} \ No newline at end of file diff --git a/内容变更记录.md b/内容变更记录.md index 8fd108c2..86b9a5ef 100644 --- a/内容变更记录.md +++ b/内容变更记录.md @@ -3,6 +3,8 @@ ## 2022-03-18 +- 新增章节内目录、评论系统,支持屏幕大小自适 +- 新增章节: [不错的unsafe队列-栈借用](https://course.rs/too-many-lists/unsafe-queue/stacked-borrow.html) - 新增章节: [不错的unsafe队列-基本操作](http://localhost:3000/too-many-lists/unsafe-queue/basics.html) - 新增章节: [不错的unsafe队列-使用miri](http://localhost:3000/too-many-lists/unsafe-queue/miri.html)