V2EX owtotwo
 owtotwo 最近的时间轴更新
owtotwo
ONLINE

owtotwo

V2EX 第 175996 号会员,加入于 2016-06-04 20:21:01 +08:00
今日活跃度排名 22916
owtotwo 最近回复了
最简化问题

先达成共识 看 nuphy 官网的宣传页面 https://nuphy.com/collections/keyboards/products/gem80 里面的图有标注键盘特色功能(主要是支持 qmk/via 以及有物理切换 Mac/Win 的开关)
我用的是 nuphy air60 v2 同一家的产品 理论上 qmk 固件的内容跟 gem80 应该是差不多的
Win 模式的默认层是第 3 层(0~7 共 8 层) 此问题不需要更多层 所以只考虑 mac 模式的层(即 0 、1 、2 层)

如果我没理解错楼主题意 即 nuphy gem80 默认的 mac 模式的默认层(0 层)的 F1~F12 默认是 mac 上的特殊功能 比如 F1 是亮度减(对应 via 的"Screen-" 在 SPECIAL 里) F3 是 task(对应 via 的"Mac Task" 在 CUSTOM 里) 单按一下 F2 就能亮度加 而 Fn+F2 键才是真正输出"F2"
但楼主希望 F2 键按一下就是"F2" 而非"Screen+" 反而 Fn+F2 键才是亮度加
Mac 模式下键盘上的 Fn 其实就是 0 层里(临时)切换至 1 层的 via 键"MO(1)" 按住切换后再按 F2 就是 1 层的 F2 键上的内容

*解:所以最直接解法就是 在原本默认没有动过 via 配置的初始情况下 将 0 层和 1 层的 F1~F12 直接一一对调 就完成楼主的需求了

补充:nuphy 因为比较往 Mac 用户上靠 所以连默认模式都是 mac 键帽图标也是 mac 的快截效果键(如 Mac Search 这个 F4 上的放大镜图标) 所以 CUSTOM 里也提供了多个 Mac 专用快捷键
另外 nuphy 的 via 就是 qmk 那个 所以能实现的效果很完整 加上对 Mac 的高适配 因此改键的自由度很高 基本你想实现的都能改(非常复杂的需要改 qmk 固件 但是应该是用不到的)

b 站搜一下 via 多层改键的视频就好了(比如 BV1jv4y1o7pk 或 BV1RV4y197s4)
对比字体渲染效果 不是应该
相同字体(如小米字体 MiSans 俩系统都改字体)
相同网页(或能调排版的软件)调好 css 字体参数(大小间隔字重等等)
同一屏幕下(24 寸 4k 苹果 hidpi 微软 200%缩放)
用手机的微距镜头拍屏幕字体吗?(非截图)
把结果图放上来 一切不就清楚了

我对现今 macOS 了解不深 还停留在几年前的黑苹果印象 但当时就是同一屏幕下(24 寸 4k)双系统(虽然都是默认字体)
因为是普通 IPS 屏 没有 oled(紫边)或其他屏幕等像素排列之类的差异
感觉苹果 UI 很舒适很有设计感和整体性 但别人提到的字体渲染问题 我感觉两者都足够清晰锐利 没有字体边缘的各种问题(不过我更喜欢苹果默认字体)
(可能印象模糊了 但 Win10 的 1909 到现在 Win11 的 23H2 我感觉新软件的高分屏缩放导致的问题愈发减少了 至少现在很舒适)
所以我的个人浅显的主观结论是 Win 的 200%缩放下字体没问题 retina 级别屏下与 masOS 差异不至于有一眼的差距
2023-10-11 15:37:51 +08:00
回复了 caobug 创建的主题 Rust RUST 所有权移动问题
@caobug #22
有讲清楚了就好 能对别人有帮助还是很开心的 : )

Rust 文章的话 不太好写 写起来时很难兼顾到不同熟练度的 Rust 小伙伴(主要还是我自己能力有限)

举个例子
就像一开始其实我想**直接**用 `while true {}`和`loop {}`为什么不一样 来解释这问题的(前者迭代 0+次 后者 1+次)
但是这样会引入题目中没提到的 while 语句 以及它们另外的差异( loop-break <value>能返回值而 while 恒为`()`之类的) 最后还得再迁移到 for 语句来解释

这样就有可能将问题复杂化了 而如果跳过中间例子直接说“const_expr 在 borrowck 阶段不求值” 不熟悉的小伙伴有可能一下子转不过来

且问题涉及 if 语句 所以最后决定用`if false {}`作例子来渐进地解释 比较好理解

Rust 文章同理 讲一个点 从多浅讲到多深 我就有点犯难了
有的知识点实在涉及太多 比如 Pin 感觉没十几页纸实在讲不清楚 一想就头都大了 0.o
2023-10-11 15:07:30 +08:00
回复了 caobug 创建的主题 Rust RUST 所有权移动问题
@DianQK #21
嗯呐 这个确实就是关键所在

若我没记错的话 似乎 rustc 的编译流程会有两次的常量折叠/传播 一次是在前端的 MIR 中 另一次是在后端如 LLVM 中
(好像是前端优化一次能降低给后端的 IR 代码复杂度)

MIR 中支持常量传播应该是比较早前的事了(或许有相关公告) 似乎是支持控制流的(代码可能在 mir 部分的 const_prop.rs ?文件名应该长得差不多)
但并不知道是否支持“消掉 if const_expr”的行为
(我不知道这种分支优化的术语应该是什么 死代码消除 Dead Code Elim ?或者是叫 Sparse Cond Const Prop ?中文可能是 稀疏条件常量传播 之类的 或许也不准确)

但比较尴尬的是 常量传播是在 MIR 的优化阶段进行的 而 borrowck 是在 mir-opt 之前进行的(如果我没记错的话)

所以正如老哥你所说的 常量传播时应该已经有借用检查了
(以及我感觉理论上应该确实是能在借用检查前算 const 的 就是不知道最终会不会增加 MIR 部分编译的总耗时)

编译流程层面的改动影响对 rustc 而言还是挺大的(如 Polonius 也只是 borrowck 部分的平替) 所以短期内可能不会有相应优化了(个人感觉 不知道目前有没有人提对应的 RFC )


以上的话并不严谨 我也暂时没能去进行校验 或许会有些错漏或过时(记忆有点旧了)

有条件的朋友或许可以补充下相关链接~
2023-10-10 15:19:35 +08:00
回复了 caobug 创建的主题 Rust RUST 所有权移动问题
@DianQK #17
或许有些区别
简单点概况,NLL(Non-Lexical Lifetimes)的迭代进化(即下一代的 Polonius)应该依然并不能解决此问题。

因为楼主这问题本质上是 rustc 编译流程的限制。如图: https://blog.rust-lang.org/images/2016-04-MIR/flow.svg
根据**目前**的编译流程,Borrow Checking 发生在 MIR 阶段,此刻的 CFG(Control-Flow Graph)仅将`if true {}`识别为`if some_cond {}`。
故而`if true { <code> }`无法等价于`loop { <code>; break }`或`{ <code> }`,因为它们的 CFG 是不一致的。(参考引用 数据流分析中的 CFG )
最后将类似`if false {}`这样的死代码消除的优化行为,是在 LLVM 的 codegen 优化阶段进行的,所以此前 borrowck 并不认识"true"或"false"。

在 Rust 2018(Rust 1.31)引入 NLL 后,生命周期的推断精度更高了,而下一代的 Polonius 会支持更复杂的控制流(Control Flow)。但是如上所述的原由,依然不能在此阶段进行条件求值,所以问题依在。

* NLL: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html#non-lexical-lifetimes
* 编译流程中的 MIR: https://blog.rust-lang.org/2016/04/19/MIR.html
* 数据流分析中的 CFG: https://github.com/rust-lang/rustc-dev-guide/blob/master/src/appendix/background.md#what-is-a-dataflow-analysis
* rustc 概览(包含各编译阶段): https://rustc-dev-guide.rust-lang.org/overview.html


我希望能由浅入深解释问题,但无法太深。前面的回答并无涉及到更多的编译器部分的具体内容,是因太冗长容易导致阅读阻力大,很少人愿意认真看(完)。(但即使现在这长度,似乎大家也习惯 tl;dr 了)

希望我有解释清楚。 : )
2023-10-08 15:54:39 +08:00
回复了 caobug 创建的主题 Rust RUST 所有权移动问题
FIX: @buxiuxi 第 9 项忘 at 了
2023-10-08 15:52:55 +08:00
回复了 caobug 创建的主题 Rust RUST 所有权移动问题
综上

6. 楼主的代码符合 Rust 的所有权规则吗?符合的,因为问题并不在所有权转移上,而是在编译期所有权检查时是否会进行具体求值的判断上。

7. @DianQK 所以**目前**而言不是 bug ,或许以后编译器更聪明效率更高了就支持此优化了。

8. @binhb @qdwang @rrfeng 的说法是对的。

9. 为啥这里 release 函数会释放 dog ?因为 fn release(self)的参数是 self ,跟 std::mem::drop()一样,调用时会获取其所有权,并在此函数结束后 drop 掉。
2023-10-08 15:40:44 +08:00
回复了 caobug 创建的主题 Rust RUST 所有权移动问题
续上

3. 对于 Code 3 ,即楼主的第一次修改尝试,实际上等价于将 loop 和 break 去掉(因为此控制流总是执行),所以必然会执行赋值语句,故而编译通过(Ok)。

4. 对于 Code 4 ,即楼主的第二次修改尝试,依然可以将 loop 和 break 去掉,此时情况等价于 Code 0 ,所以一样是编译不通过(Error)。

5. 对于 Code 5 ,即 @Kaiv2 提到的编译成功的写法,因为 break 进去 if 里了,情况就不一样了。此时控制流的逻辑只有两种情况:情况一,若不进入 if 语句里,则无限循环,那么就不会执行后面的使用 person 及 person.dog 的代码了,就没问题;情况二,进入 if 语句,则成功执行赋值,且最后必定 break 出去,执行后面的代码,依然没问题。所以这种不涉及对具体求值有依赖的控制流是能编译通过的。
2023-10-08 15:30:23 +08:00
回复了 caobug 创建的主题 Rust RUST 所有权移动问题
回到原问题,person.dog 的各种赋值写法:


0. 对于 Code 0 ,即上一条回复提到的本质问题,此处尽管写着 if true ,然而 Borrow Checker 并不默认此代码总是执行,而是认为可能执行也可能不执行。(当然,当 build release 编译优化阶段时,if true 就会被优化掉了,而所有权检查阶段并不会,或许是太耗时了)

1. 对于 Code 1 ,与 Code 0 本质一样,Borrow Checker 会认为此 for 语句可能不会执行,所以“Rust 的检测器似乎没有认真评估 for 中的条件”确实是对的,并不会在此阶段评估。

2. 对于 Code 2 ,因为有 else 分支且调用 unreachable!(),所以理论上后续使用 person 时必然已经经过 if 部分的赋值语句(因为 else 部分会 panic ,即不会执行后面代码)
2023-10-08 15:00:36 +08:00
回复了 caobug 创建的主题 Rust RUST 所有权移动问题
直接简化问题,此问题本质上,与下面代码无法编译通过的原因是一致的:


**即在编译期 Borrow Checker 是不进行具体值计算的。**

如上面的 if 分支,在生命周期检查期间,并不知道 1 == 0 总为 false 且永不执行此代码块。故而在使用 name 时,无法得知所有权是否已被转移。
甚至将 1 == 0 直接换成 false ,此期间 Borrow Checker 依旧不知道 false 总不执行代码块,即认为是**有可能**调用 drop(name)触发所有权转移的。
关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     889 人在线   最高记录 6679       Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 17ms UTC 22:25 PVG 06:25 LAX 15:25 JFK 18:25
Do have faith in what you're doing.
ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86