X



Rust part13
レス数が1000を超えています。これ以上書き込みはできません。
0001デフォルトの名無しさん
垢版 |
2021/11/07(日) 10:04:59.35ID:pJhT3MIE
公式
https://www.rust-lang.org/
https://blog.rust-lang.org/
https://github.com/rust-lang/rust

Web上の実行環境
https://play.rust-lang.org

日本語の情報
https://rust-jp.rs/

※Rustを学びたい人はまず最初に公式のThe Bookを読むこと
https://doc.rust-lang.org/book/

※Rustのasyncについて知りたければ「async-book」は必読
https://rust-lang.github.io/async-book/

※C++との比較は専用スレへ
C++ vs Rust
https://mevius.5ch.net/test/read.cgi/tech/1619219089/

※次スレは原則>>980が立てること

前スレ
Rust part12
https://mevius.5ch.net/test/read.cgi/tech/1629813327/
0002デフォルトの名無しさん
垢版 |
2021/11/07(日) 10:05:36.56ID:pJhT3MIE
Rust The Book (日本語版)
https://doc.rust-jp.rs/book-ja/
Rust edition guide (日本語版)
https://doc.rust-jp.rs/edition-guide/
Rust by example (日本語版)
https://doc.rust-jp.rs/rust-by-example-ja/
Rust cookbook (日本語版)
https://uma0317.github.io/rust-cookbook-ja/
Rust API guideline (日本語版)
https://sinkuu.github.io/api-guidelines/
Rust nomicon book (日本語版)
https://doc.rust-jp.rs/rust-nomicon-ja/
Rust WASM book (日本語版)
https://moshg.github.io/rustwasm-book-ja/
Rust embeded book (日本語版)
https://tomoyuki-nakabayashi.github.io/book/
Rust enbeded discovery (日本語版)
https://tomoyuki-nakabayashi.github.io/discovery/
0004デフォルトの名無しさん
垢版 |
2021/11/07(日) 12:23:40.47ID:yCoK9XU3

シャドーイングが困るのって関数がよっぽど長いときだけなんで問題にならんよね
0005デフォルトの名無しさん
垢版 |
2021/11/07(日) 13:02:12.62ID:BjoZRpKT
>前スレの質問「間違って同じ変数名つけたコード片突っ込んでしまった系だと他言語にあるらしい2重宣言エラーないの怖くないですか?」

他の言語でもスコープが違えば二重宣言エラーになりません
つまり他の言語でも意図しない同名変数ミスは同じように起き得ます
例えば以下はC言語の例

int c = 100;
int main() {
 int c = 200;
 {
  int c = 300;
 }
 printf("%d\n", c); /* コンパイルは通って 200 となる */
}

Rustのシャドーイングは同じブロックスコープでも同名変数が通りますが
仮にミスで同名変数を付けたコードを挿入してしまったとしても
・その時点で先行の変数が既にライフタイム尽きていれば影響ゼロ
・その時点で先行の変数のライフタイムがあって割り込む形になる場合
  ・それ以降で二度の消費が発生して借用エラー発生となる可能性が高い
  ・先行の変数が一度も使われていない段階なら未使用warning発生
  ・型が違っていれば割り込む形であっても型違いでエラー発生
と影響ゼロもしくは引っかかる可能性が高いでしょう

>>4
おっしゃる通り、そもそも意図しない同名変数に気付かない時点で「その関数は長すぎ」ですね
0006デフォルトの名無しさん
垢版 |
2021/11/07(日) 13:03:26.24ID:GwJCd0Qm
ある値をちょっとだけ処理したものにどんな名前を付けたいかってのは、
まあ適した名前があるならそれに越したことは無いけど
同じ名前を付けることによってたいした違いはない、かつ以前の値にアクセスすることはもうないことが明示できるので
それはそれで使いようはあるよ。

以前の値にアクセスしないという意思を持ってシャドーイングを使うのでそれで困ることはない。
うっかりで同じ名前を付けてしまった場合も大抵の場合は型の違いとかで検出されるし。
0007デフォルトの名無しさん
垢版 |
2021/11/07(日) 14:26:48.84ID:c7aT0NV0
何を問題にしてるのか分からんけど、コンパイラから見たら、同じ変数名宣言でも連番で構文解析しているわけで
ブロックスコープによりシャドーされても何ら関係ないが、インライン展開して最適化するrustコードだと問題が
出る場合もありうる。それとシャドーと以前の値にアクセスすることはもうない事は意味が違う
0008デフォルトの名無しさん
垢版 |
2021/11/07(日) 14:35:43.57ID:GwJCd0Qm
>>7
間接的にアクセスしうるとかいうのはもちろんあるけど、
あくまでもプログラマが読み書きする上での意図として明示するという意味ね。
実際にもう (直接には) 使えないんだから使えないという意味だよ。
0009デフォルトの名無しさん
垢版 |
2021/11/07(日) 14:45:10.83ID:K5DEbKWG
ん?まあありうるだろうけど、そんな意図を持ってシャドーイングをするコードは捨てろよ?明示じゃねーわ
0011デフォルトの名無しさん
垢版 |
2021/11/07(日) 15:10:45.19ID:XJB+ymj6
>>996
C/C++だとスコープ中で外のスコープの宣言と被ってたら警告出るよね
0012デフォルトの名無しさん
垢版 |
2021/11/07(日) 15:27:52.97ID:BjoZRpKT
>>7
>それとシャドーと以前の値にアクセスすることはもうない事は意味が違う

それはシャドーされてもスコープ終了と異なり、尽きてなければライフライムは残ってるという話だよね?
例えば
let mut a = vec![1,2,3];
let b = &mut a;
let a = [4,5,6];
b.extend(a);
assert_eq!(b, &[1, 2, 3, 4, 5, 6]);

>>11
被ってるCのコード>>5を今gcc test.cしたけどその警告出ない
0013デフォルトの名無しさん
垢版 |
2021/11/07(日) 16:09:12.89ID:XJB+ymj6
おま環
0015デフォルトの名無しさん
垢版 |
2021/11/07(日) 17:10:25.95ID:qLFsTeDp
変数名にシャドーイングって含めとけばいいのでは
0016デフォルトの名無しさん
垢版 |
2021/11/07(日) 17:23:30.13ID:BGBI+61D
そんなことよりもだ!Rustに限らないけど
これって誰も食いつかないんだけど、1と2どっちが良いか、そろそろ決着つけてくれ
let upper = 1000;
// 1、これと
let mut acc = 0;
for n in 0.. {
  let n_squared = n * n;
  if n_squared >= upper {
    break;
  } else if n_squared % 2 == 1 {
    acc += n_squared;
  }
}

// 2、これ
let acc1: u32 = (0..).map(|n| n * n)
 .take_while(|&n_squared| n_squared < upper)
 .filter(|&n_squared| is_odd(n_squared))
 .fold(0, |acc, n_squared| acc + n_squared);
0018デフォルトの名無しさん
垢版 |
2021/11/07(日) 17:29:32.83ID:TOVMzjUd
let acc1: u32 = (0..).map(|n| n * n)
 .take_while(|&n_squared| n_squared < upper)
 .filter(is_odd)
 .sum()
0019991
垢版 |
2021/11/07(日) 17:45:31.24ID:tLg/y1Lc
>>5
不意のミスでも結構コンパイルで引っかかってくれるようで安心しました。Rustさんよく考えられてますね。知りたかったことが書いてありました。ご丁寧にありがとうございます
0021デフォルトの名無しさん
垢版 |
2021/11/07(日) 18:52:44.84ID:UxYGnxuj
>>16
High orders functionはソースが配列かイテレーターか、いずれかで注意が必要です。配列の場合は以下の
英文のようになります。つまりそのサイズのメモリー領域が必要になるということです。またイテレータの
時でもある程度メモリーは当然使用しますが、それよりも遅延評価されるので注意が必要です。
Note on performance and stack usage
Unfortunately, usages of this method are currently not always optimized as well as they could be.
This mainly concerns large arrays, as mapping over small arrays seem to be optimized just fine.
Also note that in debug mode (i.e. without any optimizations), this method can use a lot of stack space
(a few times the size of the array or more).
Therefore, in performance-critical code, try to avoid using this method on large arrays or check
the emitted code. Also try to avoid chained maps (e.g. arr.map(...).map(...)).
個人的には深いチェーン呼び出しはあまり好きではありません。なぜなら状態をデバックしにくいからです。
パフォーマンス的な罠がありデバックしにくい事を抜けば、map,take_while,filterなどは何を行うかforに
比べ意図が明確になりますが、それは自己満足の幅が大きいとも言えます
0022デフォルトの名無しさん
垢版 |
2021/11/07(日) 19:20:41.26ID:AmV/cRIg
>>18のコードは大きな配列とかメモリ大量消費とかしないだろ
小さなstructを以下の4つ消費するのみで誤差
RangeFrom, Map, TakeWhile, Filter
0023デフォルトの名無しさん
垢版 |
2021/11/07(日) 19:35:16.03ID:UxYGnxuj
>>22
18のコードは配列ではなくイテレーターなのでそうですが、map,take_while,filterのほうが
好みの人が多いとは思いますが、私が言いたいのは何でもかんでもHigh orders functionに
して書くのはよく知らないと、リスクがあるということとブレークポイントなどを仕掛けて
経過は見れないということです。日本語が読めない人はもう少し考えましょう
0024デフォルトの名無しさん
垢版 |
2021/11/07(日) 19:40:56.86ID:BxmvbDqp
メソッドチェーンなら、メソッドごとに単体テストができるし、テストを用意しとけばすぐにバグがわかるような気がするが。
0025デフォルトの名無しさん
垢版 |
2021/11/07(日) 21:07:08.18ID:UxYGnxuj
ほんと日本語読めない奴ばっかり。経過いうてるのにメソッド毎だとか、バグのことなんて言って
ないのに(特殊な例を言えば配列の場合でmap().map()などとしたメモリー使用量)を言っている
のに、そもそも個人的には言うてんのに、そんなに説得したいのか?
0028デフォルトの名無しさん
垢版 |
2021/11/07(日) 21:20:10.03ID:UxYGnxuj
言語は素晴らしいのにやってる奴が意識高い系のウンコ野郎ばっかり
0029デフォルトの名無しさん
垢版 |
2021/11/07(日) 21:27:42.49ID:aMDc0Kvs
まあコミュニティに馴染めるかどうかも本人の適性によるところがあるしな
0030デフォルトの名無しさん
垢版 |
2021/11/07(日) 22:21:32.27ID:BjoZRpKT
>>25
前回から新たに導入されたfn map([T; N], FnMut(T) -> U) -> [U; N]を何度も使えば配列地獄になるけど
昔からあるIterator::map()を使えば小さな struct Mapの分しか容量を喰わないよ
前者: assert_eq!(10, [1, 2, 3, 4, 5].map(|n| n - 3).map(|n| n * n).into_iter().sum());
後者: assert_eq!(10, [1, 2, 3, 4, 5].into_iter().map(|n| n - 3).map(|n| n * n).sum());
したがってこの件でメソッドチェーンを批判するのはおかしい
そして元々の>>16課題forを使うか>>18のメソッドチェーンを使うかの話に配列は一切関係ない
0031デフォルトの名無しさん
垢版 |
2021/11/07(日) 22:27:15.28ID:jMCdC4Py
配列とスライスとベクタが別物なのこういう場所で会話するときに地味に混乱しがち
0033デフォルトの名無しさん
垢版 |
2021/11/08(月) 07:17:46.35ID:59xs5iEI
inspectで経過見れるじゃん
0034デフォルトの名無しさん
垢版 |
2021/11/08(月) 07:29:23.24ID:n6XCACTA
>>30
こういう内容ゼロの事を言ってる意識高い系が普及を邪魔してる。自身が”何度も使えば配列地獄になるけど”と
認めてるにも関わらず、最初からイテレータを使えばと先に言ってることをそのまま返す
何が”したがって”なのか全然分からんが、説明した気になり、”チェーンを使うかの話に配列は関係ない”と
まとめる。そもそもチェーンを批判なんてしてない(対象によりけり高階関数の連続使用はメモリーを圧迫する
可能性があるということだけ)それとも言い負かしたいだけの気持ち悪さをそんなに使用者に伝えたいのか?
0035デフォルトの名無しさん
垢版 |
2021/11/08(月) 07:59:01.69ID:SITQ70se
>>25
君が二つの全く異なるmap()をゴチャ混ぜにして皆を騙して混乱させているだけだ
我々はfor文で回すかイテレータをチェーンするかの話をしている
君が持ち出した[T; N]::map()は配列を配列に変換するのみでイテレータと一切関係ない
我々はmap()に関しては一貫してIterator::map()の話しかしていない
0036デフォルトの名無しさん
垢版 |
2021/11/08(月) 08:32:39.74ID:fuBvo+92
ほんとここに来るやつは皆を騙す詐欺師の気持ちや悪い奴ばかり、一切関係ないぞ!
0037デフォルトの名無しさん
垢版 |
2021/11/08(月) 10:16:54.73ID:csyRALBm
どんなに適当に書いてもコンパイラさんがうまいこと最適化してくれるのでヨシ!
0038デフォルトの名無しさん
垢版 |
2021/11/08(月) 10:32:52.09ID:xhkp7neH
最初から大して違いも出ないが、分かりやすさを重視するなら高階関数かな?
これはこう書け!と口煩くいってくる奴が理解できないけど…
でも裾野を広げるためには未熟で冗長なコードでも許容しなきゃね、1つもfor無しで
デカいプロジェクトを書くことなんて無いし、趣味でやってるだけなら縛りもありだが
0041デフォルトの名無しさん
垢版 |
2021/11/08(月) 11:23:59.38ID:OCI2yhfb
rustの得意とする高パフォーマンス領域だとactix(-web)なんかはスレッド数=物理コア数で
下手に並列化しないほうがrequest/secは高いから、標準の高階関数も並列にはなっていない
訳で、バッチ処理みたいなその時に他の処理が走ってなくて、如何に処理時間を短くするか
というプログラムなら最初からRayonとか最初に導入してそう…
状態共有しない並列起動だけなら、thread::spawn(|| { for i in 0..x {...} }でも比較的に
簡単に出来るが、そういう意味では無いんだろう
0043デフォルトの名無しさん
垢版 |
2021/11/08(月) 12:29:17.17ID:QzkUvy+x
>皆を騙す詐欺師の気持ち悪い奴ばかり

都合悪くなると話題変えて逃げるしな
0045デフォルトの名無しさん
垢版 |
2021/11/08(月) 12:45:54.28ID:ODzJsaPg
話題変えて逃げてんじゃねーよ!カス!
0046デフォルトの名無しさん
垢版 |
2021/11/08(月) 13:17:11.03ID:NiBBbin2
>>44
今のところとしてるのは改善策が取り込まれる見込みだから?
それとも単に将来のことはわからない程度の意味?
0047デフォルトの名無しさん
垢版 |
2021/11/08(月) 13:48:44.02ID:vASCcAjA
静的チェックでオールOKみたいな言語って意識高い系のバカを呼び寄せやすいんだよ。
奴らは動的テストなんてしたくないって意識をすぐ誤魔化す癖がついてる。
0051デフォルトの名無しさん
垢版 |
2021/11/08(月) 15:29:22.26ID:GGqoyJW1
うん、完全理解した。こんスレは同じrustガンダム乗りなのに連邦の白い悪魔以外は認めないんだ
どっちでもいいじゃんか・・・
https://i.imgur.com/a9pC9PS.jpg
0052デフォルトの名無しさん
垢版 |
2021/11/08(月) 17:38:09.25ID:7WV3o+af
Vecに入ったi32(空っぽの可能性もあり)の平均を計算するのってどうするのが一番スマート?
0053デフォルトの名無しさん
垢版 |
2021/11/08(月) 17:43:46.40ID:Chf4/Vgn
高階関数使う
0055デフォルトの名無しさん
垢版 |
2021/11/08(月) 21:14:06.85ID:6BzlB5w0
>>34
イテレータの高階関数の連続使用でメモリーを圧迫することはないと思います
各イテレータ自体はコンパクトな構造体ですし高階関数自体の処理も基本的にはメモリーを圧迫するものではありません
ただし全ての要素を受け取らないと算出できない物もあるため一時的に長いVecを使うことになるイテレータもあります
この場合はイテレータを用いずに自分でforなどを回す方法をとっても同様にして一時的に長いVecを使うことになるでしょう
0058デフォルトの名無しさん
垢版 |
2021/11/08(月) 21:38:34.43ID:3AO0oG+L
そんな簡単な実装を一々stdに入れてたら、糞関数だらけのLLライクになるじゃん?
0059デフォルトの名無しさん
垢版 |
2021/11/09(火) 04:01:57.70ID:d6arxLIn
>>58
std::iterに入れろとまでは思わないけど、
sumもcountもイテレータ消費しちゃうから微妙にめんどくさくない?
0060デフォルトの名無しさん
垢版 |
2021/11/09(火) 20:24:06.75ID:E/uEHC7F
>>59
こんな感じでsumとcountを同時に計算かな
trait Average<T> {
 fn average(self) -> T;
}
impl<I: Iterator<Item=T>, T: Zero + One + Add<Output=T> + Div<Output=T>> Average<T> for I {
 fn average(self: I) -> T {
  let (cnt, sum): (T, T) = self.fold((Zero::zero(), Zero::zero()), |(cnt, sum), n| (cnt + One::one(), sum + n));
  sum / cnt
 }
}
fn main() {
 assert_eq!(500, (1..1000).into_iter().average());
 assert_eq!(6.8, vec![2.3, 8.7, 9.4].into_iter().average());
 assert_eq!(33, [1, 3, 5, 7, 9].into_iter().map(|n| n*n).average());
}
0061デフォルトの名無しさん
垢版 |
2021/11/09(火) 22:53:03.40ID:yHbe3Xjs
オーバーフローしないように型を選択することとか、
汎用的に使えて問題を避けることを考えたら平均を計算するのってそんなに簡単な話ではないと思う。
0062デフォルトの名無しさん
垢版 |
2021/11/10(水) 08:15:17.85ID:BLadVH6y
stats::median
今でもfilter使えだとかうっせーのばっかり、標準ライブラリは小さくて良いYO
https://lib.rs/science/math
statrs-dev/statrsとか好きなの引っ張ってきて入れろよ?平均じゃなくてもさ
0063デフォルトの名無しさん
垢版 |
2021/11/12(金) 17:23:46.15ID:pYLNCtl5
Vecとかに入った複数のtokio::task::JoinHandleをjoinするのはどうやるんでしょうか?
0064デフォルトの名無しさん
垢版 |
2021/11/12(金) 20:00:37.76ID:PXROpwUc
thread::JoinHandleは並列で(マルチスレッドとなり)
join()で待つ

task::JoinHandleは非同期で(シングルスレッド時は並行、マルチスレッド時は並列となり)
awaitで待つ
0066デフォルトの名無しさん
垢版 |
2021/11/12(金) 23:59:03.69ID:BY1dkyYH
task::JoinHandleの方はFuture trait実装なので
列挙ならfutures::join!(f1,f2,f3,...)マクロ
VecならIntoIteratorに対応のjoin_all(v) >>65
0068デフォルトの名無しさん
垢版 |
2021/11/20(土) 19:33:51.68ID:i03LC++E
let mut a = 'a';
let mut d = 'd';

match 'b' {
 a..=d => { println!("true") }
 _ => { println!("false") }
}

matchでcharの範囲指定ができるからって試したんだけど、
変数に入れたcharだと範囲指定ってできないの?
これだとあんまり意味ないような
0069デフォルトの名無しさん
垢版 |
2021/11/20(土) 20:32:13.75ID:iQUqB4pW
パターンには代入される側の変数しか書けないけどガードは自由自在
fn test(b: char) -> bool {
 let a = 'a';
 let d = 'd';
 match b {
  _ if a <= b && b <= d => true,
  _ => false,
 }
}
fn main() {
 assert_eq!(test('b'), true);
 assert_eq!(test('x'), false);
}
0071デフォルトの名無しさん
垢版 |
2021/11/20(土) 20:49:00.01ID:iQUqB4pW
bのところが式かも知れないのでxにマッチさせてこの方がベターか
  x if (a..=d).contains(&x) => true,
0072デフォルトの名無しさん
垢版 |
2021/11/20(土) 21:28:17.44ID:i03LC++E
>>69
ありがとう 

if (a..=b).contains(&c) { println!("true") } else { println!("false"); };
って感じで試して見たけど、ガードで
(a..=b).contains(&c)にすればよさげだとわかった
0073デフォルトの名無しさん
垢版 |
2021/11/21(日) 01:21:54.59ID:VYuGYhJz
Rangeを含むジェネリックな関数を作りたいのですが例えば単純化した例
fn ntimes_print<T: num::Integer>(n: T, s: &str) {
 (0..n).for_each(|_| print!("{}", s));
}
ここでRangeのnがexpected integerと言われエラーになってしまい
上記のように型Tにnum::Integerトレイトを制約してみましたが上手くいきません
どうすれば型TとジェネリックのままRangeを使えるでしょうか?
0076デフォルトの名無しさん
垢版 |
2021/11/21(日) 02:02:32.44ID:VYuGYhJz
格闘しているうちにコンパイラがstableじゃダメだとかfeature指定しろとか無茶を言って来るので従ってnightlyにしたりfeature指定したりしたところようやく動いたのですが何か変ですよね
0077デフォルトの名無しさん
垢版 |
2021/11/21(日) 02:16:44.28ID:qtUeCPjG
うーん
引数に繰り返す回数渡せばいいような気がするんだけどそう簡単じゃないのね
0078デフォルトの名無しさん
垢版 |
2021/11/21(日) 02:30:42.73ID:VYuGYhJz
nightlyにせずstableのままで範囲指定nをジェネリック化できた方いましたらやり方教えて下さい
0082デフォルトの名無しさん
垢版 |
2021/11/21(日) 10:25:42.94ID:szj4saah
リテラル`0`の問題とstd::iter::Stepがunstableなのと2つ問題を解決する必要がある

fn ntimes_print<T>(n: T, s: &str)
where T: num::Integer + num::ToPrimitive + Clone
{
num::range(T::zero(), n).for_each(|_| print!("{}", s));
}
0083デフォルトの名無しさん
垢版 |
2021/11/21(日) 11:02:09.61ID:VYuGYhJz
やはり..を使う限りstableでは無理でnightlyでないと以下のような素朴な実装も無理ということでしょうか
少し例を実用的に変えてみましたがトレイト境界(制約)を最小限で以下のようなコードでnightlyだと動いています

#![feature(step_trait)]

fn main() {
 let n = 5; // 任意の整数型
 n.times(|n| println!("OK {}", n));
}

trait Times<T: Sized> {
 fn times<F>(self, f: F) where F: FnMut(T) -> ();
}

impl<T> Times<T> for T where T: num::Zero + std::iter::Step {
 fn times<F>(self: T, f: F) where F: FnMut(T) -> () {
  (num::Zero::zero()..self).for_each(f);
 }
}
0086デフォルトの名無しさん
垢版 |
2021/11/21(日) 16:08:27.58ID:VYuGYhJz
>>85
凄い!stableで..で動きました!ありがとう!

impl<T> Times<T> for T where T: num::Zero, std::ops::Range<T>: Iterator<Item=T> {
 fn times<F>(self: T, f: F) where F: FnMut(T) -> () {
  (num::Zero::zero()..self).for_each(f);
 }
}
0087デフォルトの名無しさん
垢版 |
2021/11/21(日) 18:59:28.56ID:a8amZ/lG
更にtimes()自体をイテレータにしてしまえば汎用的になるだけでなく
それらトレイト境界などのコードの記述も魔法のように消えて短くなる

fn main() {
 let n = 5; // 任意の整数型
 n.times().for_each(|n| println!("OK {}", n));
}

trait Times<T: Sized> {
 fn times(self) -> std::ops::Range<T>;
}

impl<T: num::Zero> Times<T> for T {
 fn times(self: T) -> std::ops::Range<T> {
  num::Zero::zero()..self
 }
}

これだけで動作する
0088デフォルトの名無しさん
垢版 |
2021/11/21(日) 20:22:13.92ID:ekMm5ue5
timesなら精々u64::MAX回も繰り返すことなさそうだしTからu64に変換するのではだめなの?
0089デフォルトの名無しさん
垢版 |
2021/11/21(日) 20:32:22.18ID:VYuGYhJz
トレイト境界が短くなって素晴らしい原因ですがもしかして
>>83では要のops::Range<T>型がコードに明示されてないので条件のiter::Stepを要求されてしまい
>>85ではそのops::Range<T>型をトレイト境界に登場させたためiter::Stepが不要となり
>>87ではそのops::Range<T>型を返り値として明記したためトレイト境界にも不要となった??
0091デフォルトの名無しさん
垢版 |
2021/11/22(月) 11:46:24.84ID:EEj8G+es
>>90
イテレータ版の方がfor_each以外とも組み合わせられるからAPIとして良いと思う

>>87
しかしトレイト境界でnum::Zeroしか求められないのはstd::ops::Range周りの設計がおかしいと思われる
普通に実装すれば初期値(num::Zero)に増分(num::One)を加えて(ops::Add)いって比較(ops::PartialOrd)が必要となる
実際にnum::rangeによるイテレータ版times()の実装は Clone + PartialOrd + num::Zero + num::One となる

fn main() {
 let n = 5; // 任意の整数型
 n.times().for_each(|n| println!("OK {}", n));
}

trait Times<T: Sized> {
 fn times(self) -> num::iter::Range<T>;
}

impl<T: Clone + PartialOrd + num::Zero + num::One> Times<T> for T {
 fn times(self: T) -> num::iter::Range<T> {
  num::range(T::zero(), self)
 }
}
0092デフォルトの名無しさん
垢版 |
2021/11/22(月) 12:13:59.22ID:qBbb57Hy
わざわざ外部crateと独自trait使って
n.times().for_each(f)にするくらいなら
(0..n).for_each(f)で十分
0093デフォルトの名無しさん
垢版 |
2021/11/22(月) 12:33:40.60ID:EEj8G+es
>>92
それでは最初の条件のジェネリックを満たせていない
>>88
状況によってはそのように強引にu64へ変換できても対応できなくなるケースもある
例えば単純な例として文字'x'からのみなる文字列による型Xを考えてみよう
#[derive(Debug,Clone,PartialEq,PartialOrd)]
struct X(String);
impl X {
 fn new(s: &str) -> Self {
  if !s.chars().all(|c| c == 'x') {
   panic!("not x");
  }
  X(s.to_string())
 }
}
これで文字'x'以外は使えない文字列の型が出来上がり
あとは>>91で必要なZeroとOneとAddを定義すれば動くはず
impl num::Zero for X {
 fn zero() -> X { X::new("") }
 fn is_zero(&self) -> bool { self.0 == "" }
}
impl num::One for X {
 fn one() -> X { X::new("x") }
}
impl std::ops::Add for X {
 type Output = X;
 fn add(self, rhs: X) -> X { X(self.0.clone() + &(rhs.0)) }
}
0094デフォルトの名無しさん
垢版 |
2021/11/22(月) 12:45:37.77ID:EEj8G+es
>>93の続き
ところがnumクレートのOneは不必要に掛け算のMulも要求してきた
仕方ないので呼び出したらパニックするimplを加える
impl std::ops::Mul for X {
 type Output = X;
 fn mul(self, _rhs: X) -> X {
  panic!("mul() for X")
 }
}
さらになぜかnum::ToPrimitiveも要求してきたのでこれもパニック実装する
impl num::ToPrimitive for X {
 fn to_i64(&self) -> Option<i64> {
  panic!("to_i64() for X")
 }
 fn to_u64(&self) -> Option<u64> {
  panic!("to_u64() for X")
 }
}
これで>>91のnum::range利用イテレータ版times()が動くはず
そういえばDisplay実装を忘れたのでDebug表示
fn main() {
 let n = X::new("xxxxx");
 n.times().for_each(|n| println!("OK {:?}", n));
}
実行結果:
OK X("")
OK X("x")
OK X("xx")
OK X("xxx")
OK X("xxxx")
ちゃんと数値型以外でも動きました
0095デフォルトの名無しさん
垢版 |
2021/11/22(月) 15:04:22.59ID:UzgCqcLK
>>93
>それでは最初の条件のジェネリックを満たせていない
ジェネリックにしたければ(T::zero()..n).for_each(f)と書けばいいだけでしょ
単にRangeを返すだけのメソッドを手間かけて微妙に抽象化しても周りが迷惑するだけだぞ
0096デフォルトの名無しさん
垢版 |
2021/11/22(月) 15:23:28.68ID:EEj8G+es
>>95
ところがT::zero()..nだと動かない
さきほどの>>93の型Xはnum::range利用だと動いたが
let n = X::new("xxxxx");
(X::zero()..n).for_each(|n| println!("OK {:?}", n));
としようとすると以下のコンパイルエラー
the following trait bounds were not satisfied:
`X: Step`
つまりnightlyでないと使えないstd::iter::Stepを満たしていないと言われる
0097デフォルトの名無しさん
垢版 |
2021/11/22(月) 19:21:50.63ID:fRCpO7Rh
どうしてもstableでやりたいという話ならRangeとStepを独自に用意するしかなさそう
n..mという表記は使えないが、n.times()なら支障なく実装できるかと

自分なら以下みたいに書くけどね
(T: From<i32> + PartialOrd が前提)

(0..).map(T::from).take_while(move ¦x¦ x<n)
0098デフォルトの名無しさん
垢版 |
2021/11/22(月) 19:36:28.33ID:3Rtka3dv
なるほどね
0099デフォルトの名無しさん
垢版 |
2021/11/22(月) 19:55:09.41ID:5egSOJea
>>97
それだとT: From<i32>という無関係で不要な強い条件を満たさないといけないため
例えば>>93の型Xでは動かないね
シンプルにZero、One、Add、PartialOrdだけで実装したほうが良さそう
0104デフォルトの名無しさん
垢版 |
2021/11/22(月) 21:09:17.05ID:fRCpO7Rh
StepがunstableなのはさておきFromLiteralみたいなトレイトがあるとZeroやOneの出番が減ってうれしいのかね
T: FromLiteralの時に整数リテラルがT型の値として解釈されるようになるようなイメージ
0106デフォルトの名無しさん
垢版 |
2021/11/22(月) 22:09:34.28ID:fRCpO7Rh
言葉足らずでしたね

struct Foo;
が FromLiteral を実装しているときに
let n: T = 123;
というコードを書くとコンパイラが
let n = T::from_literal("123");
といったコードに変換してくれるイメージ

from_literalはconst fnにできてコンパイル時にエラー検出できるとベター
0110デフォルトの名無しさん
垢版 |
2021/11/23(火) 13:56:03.32ID:b1gEfTjX
const fnが言いたいだけやろ、だれが=演算子でcopyでもなく、言語上ないことになってるコンストラクタでもなく
そんな特異なトレイトを勝手に呼ぶのが嬉しいねん、なにがバター犬や
0111デフォルトの名無しさん
垢版 |
2021/11/23(火) 14:58:36.02ID:s6k3uLQ1
>>110
= が特殊な振る舞いをするのではなくて
整数リテラルが組み込み整数型についてgenericな数値になるという振る舞いを
FromLiteralを実装した型に広げようという案のつもりです
0112デフォルトの名無しさん
垢版 |
2021/11/23(火) 20:05:14.41ID:1c3aeddQ
m..nをiter::Step使わず素直にPartialOrd + One + Addだけで実装してくれれば汎用的で分かりやすいと思う

struct Range<T> {
 start: T,
 end: T,
}
fn range<T>(start: T, end: T) -> Range<T> {
 Range { start, end }
}
impl<T: Clone + PartialOrd + One + Add<Output=T>> Iterator for Range<T> {
 type Item = T;
 fn next(&mut self) -> Option<T> {
  if self.start < self.end {
   let result = self.start.clone();
   self.start = self.start.clone() + T::one();
   Some(result)
  } else {
   None
  }
 }
}
fn main() {
 let n :Vec<u8> = range(1, 5).collect();
 let x :Vec<X> = range(X::new("x"), X::new("xxxxx")).collect();
 println!("{:?}", n); // [1, 2, 3, 4]
 println!("{:?}", x); // [X("x"), X("xx"), X("xxx"), X("xxxx")]
}
>>93のX型でも動いたよ
0113デフォルトの名無しさん
垢版 |
2021/11/23(火) 20:38:59.43ID:rocYZd+S
特徴もないリテラルを勝手に解釈するとかあり得んわ
現状だって0b0011u32とか0x80u32とか書いてるのに、型定義が横にあるからそれでコンパイル時に
パース処理したいなんてそんな都合の良い言語ちゃうだろ、Raw stringのr"123"とか、Raw bytesとか
とも違うし、確かにfrom_strが"123"を解釈するけどやるにしても、let x: i32 = "123";が通ってから。
でもコンパイル時とはいえ自動型変換に見えるコードは承認しないと思うし、直行性も下がる
こんな場末の酒場みたいな所で言ってもコミッターどころかforと高階関数で揉める駄スレにどうこう出来る内容ちゃう
0115デフォルトの名無しさん
垢版 |
2021/11/23(火) 22:14:31.32ID:qrGqDm2c
>>114
でも現実のプログラミングでは数値を生で使うよりも
struct Counter { usize } とか
struct Age { usize } とか
struct XxxLength { usize } とかにして
型が異なることをはっきりさせて安全に使いますよね
そして付加情報があればstructのフィールドが複数になることもあったり
あるいはstruct std::time::Durationのようにnanoからsecまで扱えるようにしてもAddをimplして使いますよね
つまり生の数値だけを対象にしていては視点が狭いと思うのです
0117デフォルトの名無しさん
垢版 |
2021/11/24(水) 03:12:15.58ID:P1gN11rG
Stepがstable入りしたら要らなくなる話になにとんでもない破壊的変更を持ち出しているんだ
0118デフォルトの名無しさん
垢版 |
2021/11/24(水) 03:25:07.43ID:gceGN8+W
Age型をn.times().for_each()
Length型をn.times().for_each()
Duration型をn.times().for_each()

ジェネリックw
0121デフォルトの名無しさん
垢版 |
2021/11/24(水) 17:05:44.23ID:5wn/1hS5
>>117
コンパイラや標準ライブラリの変更で型推論の結果が変わることは破壊的変更扱いされなかったっけ
0122デフォルトの名無しさん
垢版 |
2021/11/24(水) 17:26:56.67ID:Zq3lnaBh
>>106
なんとなく分かりましたがいきなりコンパイラが自動変換の前に現状で
例えばまずは整数型を例に絞ってやるとして
trait IntegerCompatible {
 type Integer;
 fn into_integer(&self) -> Self::Integer;
 fn from_integer(n: Self::Integer) -> Self;
}
こんな感じのトレイトにして
まずは利便性のために整数型自体に自分を返すよう実装しておいて
macro_rules! integer_compatible {
 ($($t:ty)*) => ($(
  impl IntegerCompatible for $t {
    type Integer = $t;
    #[inline]
    fn into_integer(&self) -> Self::Integer {
     *self
    }
    #[inline]
    fn from_integer(n: Self::Integer) -> Self {
     n
    }
  }
 )*)
}
integer_compatible! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
あとは今はコンパイラ支援がないので
使う時に自分でinto_integerして計算などして結果をfrom_integerする感じですかね
0123デフォルトの名無しさん
垢版 |
2021/11/24(水) 17:39:27.77ID:Zq3lnaBh
>>122の続き
実際に使ってみる具体例として面倒なので>>112をそのまま使うと
struct Range<T> {
 start: T,
 end: T,
}
このあたりはそのまま使うとして
fn range<T>(start: T, end: T) -> Range<T> {
 Range { start, end }
}
実装部分ではジェネリックT型にOneやAddなどを求められていたのを
CloneとIntegerCompatible要求だけに変えて整数型IにOneやAddなどを移動
impl<T, I> Iterator for Range<T> where
 T: Clone + IntegerCompatible<Integer=I>,
 I: Copy + PartialOrd + num::One + std::ops::Add<Output=I>, {
 type Item = T;
 fn next(&mut self) -> Option<T> {
  if T::into_integer(&self.start) < T::into_integer(&self.end) {
    let result = self.start.clone();
    self.start = T::from_integer(T::into_integer(&self.start) + I::one());
    Some(result)
 } else {
    None
  }
 }
}
今はコンパイラ支援がないので手動変換ですが自動もしくは簡便な記法に出来そう
あと整数型にはいちいちOneやAddやPartialOrdを書かなくても済むように出来そう
0124デフォルトの名無しさん
垢版 |
2021/11/24(水) 17:47:29.36ID:Zq3lnaBh
>>123の続き
念のため実際に使う時にどうなるかと使えるかを確認すると
let n :Vec<u128> = range(3, 7).collect();
println!("{:?}", n); // [3, 4, 5, 6]
もちろん整数型自体は使えるのは当たり前なのでLength(usize)で使う場合
#[derive(Debug,Clone)]
struct Length(usize);
impl IntegerCompatible for Length {
 type Integer = usize;
 fn into_integer(&self) -> Self::Integer {
  self.0
 }
 fn from_integer(n: Self::Integer) -> Self {
  Length(n)
 }
}
このIntegerCompatible定義はこのような単純形ならマクロ化で出来そうですね
let v :Vec<Length> = range(Length(3), Length(7)).collect();
println!("{:?}", v); // [Length(3), Length(4), Length(5), Length(6)]
そして当然ながら動きました
0125デフォルトの名無しさん
垢版 |
2021/11/24(水) 17:56:43.20ID:Zq3lnaBh
>>124の続き
あとは>>93に出てきた変なX型ですね
#[derive(Debug,Clone)]
struct X(String);
impl X {
 fn new(s: &str) -> Self {
  if !s.chars().all(|c| c == 'x') {
    panic!("not x");
  }
  X(s.to_string())
 }
}
と定義はそのまま使っておきます
あとはOneやAddの実装はをせずにIntegerCompatibleだけ実装
impl IntegerCompatible for X {
 type Integer = usize;
 fn into_integer(&self) -> Self::Integer {
  self.0.len()
 }
 fn from_integer(n: Self::Integer) -> Self {
  X::new(&std::iter::repeat("x").take(n).collect::<String>())
 }
}
このような特殊例のみIntegerCompatible実装のマクロ化は無理ですね
let v :Vec<X> = range(X::new("xxx"), X::new("xxxxxxx")).collect();
println!("{:?}", v); // [X("xxx"), X("xxxx"), X("xxxxx"), X("xxxxxx")]
当然ですがX型についても動きました
0128デフォルトの名無しさん
垢版 |
2021/11/24(水) 23:19:00.01ID:e1u6MioL
結局Derefみたいにコンパイラが自動的に適用して変換してくれればそのintoやfromをプログラムには書かなくて済むんやろ
0129デフォルトの名無しさん
垢版 |
2021/11/25(木) 23:08:27.91ID:QVGqalzl
ファイルを開く操作って普通に考えたらFile::open_ほにゃらら()みたいなメソッドにOpenOptionsを渡すほうが自然だと思うんですが
OpenOptions::open()みたいな方法を取ってるのってどういう理由からなんでしょうか?
0130デフォルトの名無しさん
垢版 |
2021/11/25(木) 23:59:01.72ID:88pS2ZzI
>>129
・その方がメソッドチェーンで見やすい
・複雑な構造体を用意してそこに様々な値をセットして指定するインターフェースは非常に大変
・そのうえOS毎に違う部分もある
0131デフォルトの名無しさん
垢版 |
2021/11/26(金) 00:22:31.18ID:aH1+xhzE
>>129
Rustは関数定義でデフォルト値のあるオプション引数をサポートしてないから
オプション引数的な使い方をしたい場合はビルダーパターンを使うのが一般的

File::options().read(true).create(true).open("foo.txt”);みたいな使い方になる
0133デフォルトの名無しさん
垢版 |
2021/11/26(金) 09:50:01.95ID:kuMbCEJE
メソッドチェーンって過去の遺物だよね?
バグの温床だし
長いとどこかで消し忘れや二重指定が出て本人が気が付かなくなる
長くなっただけで破綻するんだからおかしい
0134デフォルトの名無しさん
垢版 |
2021/11/26(金) 10:00:30.74ID:5+U4u14D
>>133
一般的に今どきのプログラミング言語は全てメソッドチェーンが主流
もしかしてメソッドチェーンを使わない古い言語使いの方ですか?
0136デフォルトの名無しさん
垢版 |
2021/11/26(金) 10:12:22.08ID:kuMbCEJE
え?メソッドチェーンってjqueryが流行ってたころの名残でしょ?
10年ぐらい前

メソッドチェーンなんて書いててだるいだけ
0137デフォルトの名無しさん
垢版 |
2021/11/26(金) 10:21:37.95ID:5+U4u14D
>>136
JavaScriptも今は関数型プログラミングが主流へと変わりメソッドチェーンだし外部ライブラリを使うインタフェースもメソッドチェーンがよく使われる
そしてRustも同様
どこの古い世界から来たお客さんですか?
0138デフォルトの名無しさん
垢版 |
2021/11/26(金) 10:34:43.95ID:E7I1X7f8
メソッドチェーンって関数型由来ではないし
0139デフォルトの名無しさん
垢版 |
2021/11/26(金) 11:18:59.37ID:/IsoxS9R
>>133
ビルダーは二重指定しても問題ない
消し忘れはどういう指定方法でも発生するからテストで防ぐ以外ないよ

テスト書かない文化の人?
0143デフォルトの名無しさん
垢版 |
2021/11/26(金) 12:05:35.16ID:SqSfLhr2
>>132
どうやったら綺麗なのか参考のため教えて
Rustじゃなくて他の言語でも
仮想の言語でもいいよ
0144デフォルトの名無しさん
垢版 |
2021/11/26(金) 12:25:05.02ID:kuMbCEJE
通常のCのオープン関数のほうが100倍キレイで簡潔で合理的だと思うが個人差はあるんだろうな


File::options().read(true).create(true).open("foo.txt”);

これを書くときにリードがtrueだな、createもtrueだな、そしてファイル名はfoo.txtだと言う思考順序で
コード書くとは思えないんですよ常識的に
0145デフォルトの名無しさん
垢版 |
2021/11/26(金) 12:29:19.27ID:kuMbCEJE
これが美しいと言う人はそれこそ逆ポーランド次元から来た異次元人だと思うよ
0147デフォルトの名無しさん
垢版 |
2021/11/26(金) 12:43:09.59ID:GoGODfBQ
おまいら日本語否定ですか。


>>144は設計が悪いんじゃない?

File::options().readwrite().newfile().open("foo.txt”);

なら自然だろ。
>>144
0149デフォルトの名無しさん
垢版 |
2021/11/26(金) 12:53:26.61ID:kuMbCEJE
ファイルを開こうと思うときにoptions型から思考がスタートする人は天才なんだろうな
それか飼いならされた人
0150デフォルトの名無しさん
垢版 |
2021/11/26(金) 12:57:20.12ID:kuMbCEJE
言語否定じゃなくてライブラリ設計がおかしい
実用無視の人が設計するとこうなる
0151デフォルトの名無しさん
垢版 |
2021/11/26(金) 12:58:29.05ID:Q6WyUjPa
File::open_with_options("foo.txt", &OpenOptions::new().read(true).create(true));

どっちが良いとか悪いとかじゃないと思うがなあ
0153デフォルトの名無しさん
垢版 |
2021/11/26(金) 13:13:45.37ID:HMe+psgI
OpenOptionsって名前で明らかに「ファイル開く時のオプションですよ」って名前なのにファイル開く操作まで持ってるから気持ち悪いんだよな
同じモジュールでディレクトリはDirBuilderとかあるんだから普通にFileBuilderとかにすりゃええやんとか思っちゃうけどなんか理由があったんかね
0154デフォルトの名無しさん
垢版 |
2021/11/26(金) 13:23:36.09ID:kuMbCEJE
確かに他だったらoptionのインスタンスを作ってopenに食わせる感じだな
それもどうかと思うけど
ほぼ定数みたいなものをわざわざ作って食わせるなんて
0155デフォルトの名無しさん
垢版 |
2021/11/26(金) 14:04:50.29ID:TIzT5fn9
慣れない人にとっては分かりにくいAPIにならざるを得ないのは確か

ただ他の言語でオプション引数やオーバーロードが2桁あるのが当たり前になってるようなライブラリを見るとそれぞれ一長一短あるなとは思う
0157デフォルトの名無しさん
垢版 |
2021/11/26(金) 14:20:28.16ID:Ye0bskEh
>>153
OpenOptionsはrust1.0以前からあるものなのでその頃はビルダーのイディオムがなかったのだと思う
DirBuilderはrust1.6で追加されたものなので比較的新しい
0158デフォルトの名無しさん
垢版 |
2021/11/26(金) 14:57:24.65ID:AxmLr4ZJ
> 通常のCのオープン関数のほうが100倍キレイで簡潔で合理的

さっぱりわからんけどw
別に
File::options().readwrite().newfile().open("foo.txt”);
がいいとも悪いとも思わんし
cのopenがいいとも悪いとも思わん
どんな素晴らしいopen見せてくれるのかと思ったらガッカリした
0159デフォルトの名無しさん
垢版 |
2021/11/26(金) 15:03:20.08ID:BGloBCeB
OpenOptionsが分かりにくいってのはそのとおりだと思うし、実際みんなそう思ってるみたいで
ちょうどFile::optionsにするRFCが通るところだよ
0162デフォルトの名無しさん
垢版 |
2021/11/26(金) 19:18:40.42ID:wVYXipKz
>>161
それはfopenの仕様(引数の意味とか)を知っているのが前提だからなぁ。
filenameとmodeの順番を間違えたら読み間違える。
メソッドチェーンと比較するなら名前付き引数のメソッド呼び出しじゃない?
あるいはインテリセンス環境下という条件付きか。
0163デフォルトの名無しさん
垢版 |
2021/11/26(金) 19:21:46.75ID:Hq7eoo6P
>>161
ほんそれ
0164デフォルトの名無しさん
垢版 |
2021/11/26(金) 19:26:21.35ID:kuMbCEJE
仮想のコードで例が適切かどうかわからないけど

File::options().readwrite().newfile().read().open("foo.txt”)

と書いて直後で書き込めねえええええよと叫ぶよりfopenの方がいいだろ;
0165デフォルトの名無しさん
垢版 |
2021/11/26(金) 19:37:54.04ID:kuMbCEJE
あ、ミスった


それはさておき例のメソッドチェーン見ても瞬時に不安しかよぎらない

readwrite() が中で read(true).write(true) してるとして
readonly() が中でread(true)しかしてないんじゃないかとか不安
0166デフォルトの名無しさん
垢版 |
2021/11/26(金) 19:47:03.96ID:AxmLr4ZJ
>>162
> 名前付き引数のメソッド呼び出しじゃない?

俺も最初はそう言う話が出てくるのかとおもったら
cのopenを有りがたがってる奴が出てきて呆れた
0167デフォルトの名無しさん
垢版 |
2021/11/26(金) 20:09:04.42ID:XtGzaRsE
>>134
メソッドチェーンと関数チェーン|パイプラインが区別できてないんでは?
メソッドチェーンってレシーバの記述を省略できるとか文の数が減るとかでしかないでしょ。
0169デフォルトの名無しさん
垢版 |
2021/11/26(金) 20:42:02.78ID:kuMbCEJE
cのfopenはメソッドチェーンより簡潔だ

本当は他の言語のenumでいいんだけど

Open("rust.txt",FileMode.Open, FileAccess.Read)
これでバグは出ない
0171デフォルトの名無しさん
垢版 |
2021/11/26(金) 21:02:27.39ID:Ye0bskEh
foo(true, false, true, false) や foo(None, None, None, Some(true)) みたいな呼び出しよりは100倍マシ
0173デフォルトの名無しさん
垢版 |
2021/11/27(土) 00:09:21.90ID:riEP2Tv6
OpenOptionsの名称問題はともかく
なぜメソッドをチェーンさせているかというと理由は明白で
OpenOptionsExtトレイトをuseすると使えメソッドが拡張されて.mode()などが使えるようになるからだよ
0176デフォルトの名無しさん
垢版 |
2021/11/27(土) 00:42:49.16ID:w5eY7K13
チェーンの話なら、出来るだけチェーン派が多いけど.NETのLINQみたいになったら嫌?
それとも歓迎?LINQ形式のほうが分かりやすい。前の高階関数の話もそうだけど…
OpenOptionsはなんでもかんでもトレイトの弊害の気もする
articles =
  from a in articles
  orderby a.published descending
  select new article_st;
https://github.com/StardustDL/Linq-in-Rust
let e: Vec<i32> = linq!(from p in x.clone(), where p <= &5, orderby -p, select p * 2).collect();
このプロジェクトはcloneしてしまうところがダサいが、MSが参画しているということはありうるわけで
0177デフォルトの名無しさん
垢版 |
2021/11/27(土) 00:54:31.43ID:tWlgYd9Y
>>173
元がこうだもんな
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
そしてunix以外にも対応するために
std::os::unix::fs::OpenOptionsExtへ分けたのだろう
このメソッドチェーンビルダー方式以外のAPIでは詰む
0178デフォルトの名無しさん
垢版 |
2021/11/27(土) 05:50:15.37ID:IOkCeWcH
>>176
LINQはSQL風になる糖衣構文だからちょっと違うんちゃう。Rustに導入されても他の世界感と異質だし……。
個人的にはあれがSQL屋以外に直感的とは思えないw
0180デフォルトの名無しさん
垢版 |
2021/11/27(土) 11:01:40.71ID:kX7QbhiL
それはElixirと同じ「なんちゃってパイプライン」でメソッドチェーンが実現できるというだけでは。
ここで欲しいと言われているのは大元のF#のように自由関数やその部分適用が使えるパイプラインのことだろう。
0183デフォルトの名無しさん
垢版 |
2021/11/27(土) 15:58:50.40ID:lc2cVbH3
自由関数ってなんだっけ?
自由変数ならわかるんだけど
0185デフォルトの名無しさん
垢版 |
2021/11/27(土) 16:36:46.11ID:kX7QbhiL
何気なく使ってたけど調べてみたらC++用語だったか。しかも日本じゃ「フリー関数」という表記の方が一般的なんだな。
メンバー関数(メソッド)ではない素の関数ということで。
0187デフォルトの名無しさん
垢版 |
2021/11/27(土) 17:20:05.91ID:kX7QbhiL
そっちか。
Elixirのパイプラインの使用例でよく見る形式が部分適用とは違うんで使えないものと思っていた。すまん。
部分適用は別の表記になるんだな。
0189デフォルトの名無しさん
垢版 |
2021/11/27(土) 18:21:56.04ID:molZfSEM
>>178
そうは言っても現状の下のこれが直感的に分かり易いとは思えないけど、、LINQはSQLとは関係ないよ。
whereとかselectがそれに見えるけど、言語的には直行性を高めた統合クエリなだけ
let mut y: Vec<i32> = x.clone().filter(|p| p <= &5).collect();
y.sort_by_key(|t| -t);
let y: Vec<i32> = y.into_iter().map(|t| t * 2).collect();
0190デフォルトの名無しさん
垢版 |
2021/11/27(土) 19:30:03.08ID:tWlgYd9Y
>>189
どこが見にくいのか具体的に教えて
use itertools::Itertools;
let y: Vec<i32> = x
 .filter(|p| p <= &5)
 .sorted_by_key(|t| -t)
 .map(|t| t * 2)
 .collect();
0191デフォルトの名無しさん
垢版 |
2021/11/27(土) 21:12:33.33ID:VfaT4D+K
>>185
> 何気なく使ってたけど調べてみたらC++用語だったか

どこの世界に非メンバ関数をフリー関数という馬鹿がいるのか詳しく
CかC++の規格のどこを参照すれば定義されているのか詳しく
0196デフォルトの名無しさん
垢版 |
2021/11/27(土) 21:44:30.32ID:lc2cVbH3
馬鹿っていちいち言うなよ
素直になれや
0197デフォルトの名無しさん
垢版 |
2021/11/27(土) 22:07:33.35ID:tWlgYd9Y
その「フリー関数」とはクラスのメンバー関数ではない非メンバー関数として
クラスのないRustではその非メンバー関数の定義はどうなるの?

例えば以下のprint_all()は適当に作ったトレイトPrintAllのメンバーかもしれないけど
現実には('a'..='z').print_all();が動作してしまうわけで『誰のメンバー関数』なの?それとも非メンバー関数?
trait PrintAll<T> {
 fn print_all(self);
}
impl<I: Iterator<Item=T>, T: Display> PrintAll<T> for I {
 fn print_all(self: I) {
  self.for_each(|x| println!("{}", x));
 }
}
0199デフォルトの名無しさん
垢版 |
2021/11/27(土) 22:24:30.93ID:dpgg2nfE
メソッド呼び出しできない関数は「フリー関数」ってことでええんちゃう?
非メンバ関数って呼ぶほうが断然一般的だとは思うが
0200デフォルトの名無しさん
垢版 |
2021/11/27(土) 22:47:33.66ID:riEP2Tv6
>>197
selfがIteratorだからクラス志向だとprint_all()はIteratorクラスのメンバーかな
しかしそのPrintAllはIteratorを継承してないから難しい
0201デフォルトの名無しさん
垢版 |
2021/11/27(土) 23:15:00.42ID:udgmz45E
https://dev.to/mindflavor/rust-builder-pattern-with-types-3chf
この手のPhantomDataとジェネリクス使って特定の条件満たした状態じゃないとbuildとかのメソッドが実装されないようにしたりしたビルダーパターンってここの人たちはどう思ってる?

説明だけ見るとめっちゃ良いやん!って思うけどいざ自分で書くとメリットに対して無駄に複雑&使う側としてもエラーが見にくいとかなんか微妙に感じちゃう
0202デフォルトの名無しさん
垢版 |
2021/11/28(日) 00:27:08.53ID:j8Nrs0jp
>>200
例えばこのように任意の実装が出来るからprint_all()はIteratorのメンバーではなくあくまでもPrintAllのメンバー
struct V<T>(Vec<T>);
impl<T: Display> PrintAll<T> for V<T> {
 fn print_all(self) {
  self.0.into_iter().for_each(|x| println!("{}", x));
 }
}
0204デフォルトの名無しさん
垢版 |
2021/11/28(日) 00:54:44.73ID:j8Nrs0jp
>>201
長くて斜め読みしかしていないがもっとわかりやすく示すとこういうことか

まず状態を示すダミーな型を作っておく
trait State {}
impl State for ToDo {}
impl State for Done {}
#[derive(Debug)]
struct ToDo;
#[derive(Debug)]
struct Done;

次にビルダーの構造体にダミーな型も収容する (サイズはゼロ)
type PD<T> = std::marker::PhantomData<T>;
#[derive(Debug)]
struct Builder<SetA: State, SetB: State> {
 a: i32,
 b: i32,
 _a: PD<SetA>,
 _b: PD<SetB>,
}
つまり変数aがセットされたか否かの状態をダミーな_aの型で示す
(つづく)
0205デフォルトの名無しさん
垢版 |
2021/11/28(日) 00:58:02.64ID:j8Nrs0jp
>>204の続き
初期値ToDoで開始してセットされたらDoneに変える
impl<SetA: State, SetB: State> Builder<SetA, SetB> {
 fn new() -> Builder<ToDo, ToDo> {
  Builder { a: 0, b: 0, _a: PD {}, _b: PD {}, }
 }
 fn set_a(self, a: i32) -> Builder<Done, SetB> {
  Builder { a, b: self.b, _a: PD {}, _b: PD {}, }
 }
 fn set_b(self, b: i32) -> Builder<SetA, Done> {
  Builder { a: self.a, b, _a: PD {}, _b: PD {}, }
 }
}

全部がDoneになった時だけ実行可能にしておく
impl Builder<Done, Done> {
 fn execute(&self) {
  println!("OK: {:?}", self);
 }
}

最初の呼び出しをわかりやすく用
fn new_builder() -> Builder<ToDo, ToDo> {
 Builder::<ToDo, ToDo>::new()
}

あとは両方がセットされると実行できる
fn main() {
 new_builder().set_a(123).set_b(456).execute();
}
片方でもセットを忘れるとコンパイル時にexecute()が解決できず失敗する
自分でこのコードを毎回間違えずに書くのは面倒なのでマクロ化されるなら採用
0207デフォルトの名無しさん
垢版 |
2021/11/28(日) 02:33:07.17ID:ZOlCZyFx
>>201
こういうのは手書きするのではなくて derive で良い感じに実装してほしい
あとrustdocの出力がごちゃつきそうなのが気になる
0209デフォルトの名無しさん
垢版 |
2021/11/28(日) 02:48:11.47ID:Fw4ypgsa
config部分が静的に決まってるならいいけど
UIやコマンドラインから動的にconfigしたい場合Builder traitを用意してtrait objectとして持ち回して
.execute()するためにdowncastする必要が……とかで二度手間になりそう
0211デフォルトの名無しさん
垢版 |
2021/11/28(日) 10:39:31.01ID:XbegH2kB
>>201
難しい話をすると
ビルダはディレクタに対して抽象化されており
一個のディレクタが複数のビルダをケアできることを考えると
必須パラメータというのをビルダ実装ごとに準備するなら
ビルダというインタフェースがディレクタに対して実質破綻してると思う
でも
ビルダインタフェースが正しい呼び出し順を想定してたりするのをアリとするなら
必須パラメータも同じように勝手に想定しておいて
使う側にはドキュメントなりなんなりで勝手に指示だしとけば十分とも思う
そんで
呼び出し順や必須か否かに想定を置きたくない
呼び出し側に完全な自由度を与えたビルダインタフェースを提供したいなら
インタフェース Fooビルダ {Fooビルダ a(); Fooビルダ b();}
クラス 実際のビルダ implements Fooビルダ {
Foo(必須な何か x) {略} // コンストラクタで与えるとか
Fooビルダ 必須なc() {略} /* 実際のビルダ固有のメソッドとして与えて
new 実際のビルダ().必須なc().a() などと呼ぶか
Fooビルダ a() {略}
Fooビルダ b() {略}
Foo create() {略}
}
のようにして、ビルダインタフェース側だけはクリーンに守っておけばスッキリかも?
元のURLにあるように何が必須かをパラメータ化したいという欲求は解消してないのは認める
0213デフォルトの名無しさん
垢版 |
2021/11/28(日) 23:35:20.49ID:Fzo1fdIE
ここまで意味不明な文章書けるのって逆に凄いよ
このレベルは久々に見たわ
0214デフォルトの名無しさん
垢版 |
2021/11/29(月) 01:53:08.06ID:zo5XubVi
Javaコードの識別子の部分を日本語で書いて
GoFのオリジナルのBuilderパターンを説明しただけっぽい

なんでRustスレでそんな話をしたのかだけは完全に謎だが……
0215デフォルトの名無しさん
垢版 |
2021/11/29(月) 02:06:35.83ID:27e/xIh/
普通のBuilderであまり困ったことないからなあ

操作によって遷移していく状態があって、状態ごとに可能な操作が違う(呼び出せるメソッドが違う)とかなら意味あると思う(Socketのbind->accept->read/writeみたいな)
ただこういうものはもはやBuilderと呼ぶべきものではないと思う
0218デフォルトの名無しさん
垢版 |
2021/11/29(月) 16:49:12.44ID:4MgUQE5v
>>217
もっと単純に let z: *mut i8 = *s; も通らないので
これはDerefMutの条件であるmutable contextを満たしてないのではないか
そしてもちろん let z: &mut i8 = *s; は通るし **s = 88; も通るからDerefMut自体は機能している
0221デフォルトの名無しさん
垢版 |
2021/11/30(火) 18:31:42.77ID:8WvE/rry
ifの閉じカッコにセミコロンが必要となる条件を教えてください
以下のプログラムはそれが足りないと指摘されてコンパイルエラーとなり
セミコロンを付けると通って動作するのですがどういう原理なのでしょうか?
fn main() {
 for line in BufReader::new(io::stdin()).lines() {
  let line = line.unwrap();
  if let [first, second, rest] = line.splitn(3, ' ').collect::<ArrayVec<_, 3>>()[..] {
   println!("{}:{}:{}", first, second, rest);
  }
 }
}
0223デフォルトの名無しさん
垢版 |
2021/11/30(火) 20:27:35.13ID:s7fhQ2Tk
ブロック式最後の式の値は、ブロック式の値として返るので drop されるタイミングがブロックの末尾よりも後の箇所になるということかな
for のブロックは値を返さないけど、ブロック式と同じ扱いをされているっぽい
https://play.rust-lang.org/?version=stable&;mode=debug&edition=2021&gist=b5639623c9a0dff8426f1d38b7123fdc
0224デフォルトの名無しさん
垢版 |
2021/11/30(火) 21:12:32.45ID:8WvE/rry
>>223
>> ブロック式最後の式の値は、ブロック式の値として返るので

もちろんおっしゃる通りでその例でも>>221の例でもif式の値は明瞭に()ですね

>> drop されるタイミングがブロックの末尾よりも後の箇所になるということかな

ブロック式の値として返るのは()ですから変数lineのdropタイミングが後にはならないように思うのですがどうなのでしょう?
0225デフォルトの名無しさん
垢版 |
2021/11/30(火) 21:32:53.10ID:hx6pGpzB
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped

↑エラーメッセージに理由書いてるよ
0226デフォルトの名無しさん
垢版 |
2021/11/30(火) 21:55:20.40ID:8WvE/rry
>>225
そのエラーメッセージでは理由になっていないのではないでしょうか?

例えば(for文を使わない)>>223の以下の部分を
if let [_first, _second, _rest] = line.splitn(3, ' ').collect::<ArrayVec<_, 3>>()[..] {}

このように2行へ書き換えても同じくセミコロンを付けろエラーとなりますが
let x = line.splitn(3, ' ');
if let [_first, _second, _rest] = x.collect::<ArrayVec<_, 3>>()[..] {}

このように2行へ書き換えるとコンパイルが通ります
let x = line.splitn(3, ' ').collect::<ArrayVec<_, 3>>();
if let [_first, _second, _rest] = x[..] {}

この差をどう見るのか教えていただけますでしょうか
0227デフォルトの名無しさん
垢版 |
2021/11/30(火) 22:02:05.25ID:s7fhQ2Tk
>>224
・lineの寿命はif-let式の寿命と一致する
・ブロックの最後の文の寿命はブロックを囲む文の寿命と一致する
という仕様になっていると思われる
型は関係なくてブロック内の最後の式か否かが重要
0228デフォルトの名無しさん
垢版 |
2021/11/30(火) 22:26:55.08ID:hx6pGpzB
>>226
>このように2行へ書き換えるとコンパイルが通ります
>let x = line.splitn(3, ' ').collect::<ArrayVec<_, 3>>();

line.splitnでborrowしたものを使ってるtemporaryは
let xで受けたタイミングでtemporaryじゃなくなる
(エラーメッセージにあるdropped soonerの状態になってる)

if式がブロックの最後の式でそのif式の一部がborrowを使ってるtemporary
セミコロンがないとtemporaryが解放される前にローカル変数のlineが解放されるからライフタイムのエラー

そのうち修正されるかもしれないけど今はそういう動きってこと
0230デフォルトの名無しさん
垢版 |
2021/11/30(火) 22:35:06.87ID:hx6pGpzB
すまん、投稿ミス。

値を返したいときはセミコロンを追加するだけじゃだめだから
一旦変数で受けてからその変数をブロックの最後に書く
0231デフォルトの名無しさん
垢版 |
2021/11/30(火) 22:39:09.24ID:8WvE/rry
ふむむ
lineがヒープにあると以下の2行だけでセミコロン付けろエラーになりますね
let line = String::from("A B C D E");
if let [_first, _second, _rest] = line.splitn(3, ' ').collect::<ArrayVec<_, 3>>()[..] {}

このif let文を例えば以下のように変えるとセミコロンを付けなくても通るのはどうしてでしょう?
if let Some(_s) = line.get(3..6) {}
0232デフォルトの名無しさん
垢版 |
2021/11/30(火) 22:41:34.40ID:rIKeeiBO
なんでセミコロン付けると一時オブジェクトの寿命変わるんだって思ったけどそういえばC++にもそんな仕様あったな……
完全式じゃなくて戻り値に使うから破棄されないってことか
0236デフォルトの名無しさん
垢版 |
2021/12/01(水) 16:06:22.55ID:oI4zTDt2
>>234
BufReadはReadに対して追加の機能(行単位の読み込みなど)があるけど
Writeに対して追加すべき機能がないからBufWriteは存在しないのではないかと思われる
0237デフォルトの名無しさん
垢版 |
2021/12/01(水) 21:58:24.00ID:QwFnQ8Qa
flushしなけりゃ下のレイヤのどこかで勝手にバッファリングされることがほとんどだから用意する意味がないんだろな。
0238デフォルトの名無しさん
垢版 |
2021/12/01(水) 23:34:44.63ID:hYYowF9a
>>237
いやBufWriteトレイトが存在しないだけであってBufWriterはちゃんとある
そしてBufWriterがバッファリングする最後の要
誰かが勝手にバッファリングしてくれることはない
例えば何行もファイルに書き込む時にBufWriter使わずに各行毎にwriteしてたら遅くなる
0240デフォルトの名無しさん
垢版 |
2021/12/03(金) 14:45:17.46ID:RidNMi7I
REPL的にコードスニペットの実行確認するために使ったりはできるのかな
今はplaygroundで事足りているが
0241デフォルトの名無しさん
垢版 |
2021/12/04(土) 15:22:12.31ID:f29/w5s1
Read::read_to_end()に空のVecを渡した時に戻り値のusizeとVecのlen()が違う値になる事って有り得ますか?
0242デフォルトの名無しさん
垢版 |
2021/12/04(土) 23:32:14.41ID:VZLpyp2B
同じと思う
let file_size = file.metadata().map(|m| m.len())?;
let file_pos_before = file.stream_position()?;
let read_buf_size_before = read_buf.len();
このようなfileとread_bufがある任意の状況で
let read_size = file.read_to_end(&mut read_buf)?;
とread_to_end()すると以下が常に成り立っていると思われる
assert_eq!(read_buf_size_before + read_size, read_buf.len());
assert_eq!(file_pos_before + read_size as u64, file_size);
0243デフォルトの名無しさん
垢版 |
2021/12/05(日) 23:43:02.39ID:+2NbegRW
> loop式はbreakで指定した値を返せるのに
> なぜwhile式やfor式は値を返せないの?
> Option型にしてbreakで値を指定した時だけSome(値)としてそれ以外はNoneとすれば便利なのに

そのloopと組み合わせればよい
(例)
let r = 'result: loop {
 for x in 1..100 {
  for y in 1..100 {
   if x * y > 1234 {
     break 'result Some((x, y));
   }
  }
 }
 break 'result None;
};
assert_eq!(r, Some((13, 95)));
0244デフォルトの名無しさん
垢版 |
2021/12/06(月) 12:54:15.14ID:BduPW1Ae
>>243
forよりイテレータを繋げた方が単純でわかりやすいよ!と言おうとしたら
let r = (1..100)
 .map(|x| (1..100)
  .map(|y| (x, y))
  .find(|(x, y)| x * y > 1234)
 )
 .find(|o| o.is_some())
 .map(|oo| oo.unwrap());
assert_eq!(r, Some((13, 95)));
むしろ複雑でわかりにくくなってしまったw
まさかの>>243のダミーloop使用がベストアンサーなのか!?
0247デフォルトの名無しさん
垢版 |
2021/12/06(月) 15:59:22.06ID:BduPW1Ae
結局見やすくこう書けるといいんだよね
let r = pair(1..100, 1..100).find(|(x, y)| x * y > 1234);
assert_eq!(r, Some((13, 95)));
これでassertも通ったけどyのイテレータとx自身の2ヶ所にCloneが必要となってしまった
避けられないような気がするけどどうでしょうか?
fn pair<IX: Iterator<Item=X>, IY: Iterator<Item=Y> + Clone, X, Y>(ix: IX, iy: IY) -> Pair<IX, IY, X, Y> {
 Pair { cur_ox: None, cur_iy: iy.clone(), ix: ix, iy: iy, }
}
struct Pair<IX: Iterator<Item=X>, IY: Iterator<Item=Y>, X, Y> {
 cur_ox: Option<X>, cur_iy: IY, ix: IX, iy: IY,
}
impl<IX: Iterator<Item=X>, IY: Iterator<Item=Y> + Clone, X: Clone, Y> Iterator for Pair<IX, IY, X, Y> {
 type Item = (X, Y);
 fn next(&mut self) -> Option<Self::Item> {
  loop {
    if let None = self.cur_ox {
     self.cur_ox = self.ix.next();
    }
    if let Some(ref x) = self.cur_ox {
     if let Some(y) = self.cur_iy.next() {
      break Some((x.clone(), y));
     } else {
      self.cur_ox = None;
      self.cur_iy = self.iy.clone();
      continue;
     }
    } else {
     break None;
    }
  }
 }
}
0248デフォルトの名無しさん
垢版 |
2021/12/06(月) 16:01:51.04ID:NQsvo9rr
最近知ったボクの大発見書いていい?
let a: Option<i32> = None;
これは
let a = None::<i32>;
と書ける
関数のパラメータとして渡そうとして
f(None)で怒られたとき
f(None::<i32>)として怒られない

しょうもないレス失礼いたしました
0249デフォルトの名無しさん
垢版 |
2021/12/06(月) 16:21:14.38ID:BduPW1Ae
>>248
曖昧性を確定させる::<型>の指定は色々なところで出てくるね
例えばcollect::<Vec<_>>()とか
ブロックやクロージャの返り値でOk::<(),std::io::Error>(())とか
0252デフォルトの名無しさん
垢版 |
2021/12/06(月) 17:09:45.91ID:Fu08U5Ef
>>248
型パラメータは Option のパラメータなので順当に考えれば Option::<i32>::None と書くべきだし実際にそれで通るんだけども、
歴史的経緯でバリアントにも付けられるようになってる。

短く書けるから習慣的にはバリアントに型を付けるほうが多いかな……?
0253デフォルトの名無しさん
垢版 |
2021/12/06(月) 17:31:38.25ID:BduPW1Ae
>>250
なるほど直積集合かぁ
同じくyのイテレータとxはCloneを要求してますね
fn cartesian_product<J>(self, other: J) -> Producfgt<Self, J::IntoIter>
where
 Self: Sized,
 Self::Item: Clone,
 J: IntoIterator,
 J::IntoIter: Clone,
0254デフォルトの名無しさん
垢版 |
2021/12/06(月) 20:06:32.13ID:NQsvo9rr
>>249
> Ok::<(),std::io::Error>(())とか

正直見たことなかったです

>>252
> 歴史的経緯でバリアントにも付けられるようになってる。

(´・∀・`)ヘー
そういうわけなんですね
0255デフォルトの名無しさん
垢版 |
2021/12/06(月) 21:47:08.33ID:BduPW1Ae
>>254
例えばlet x = spawn(async { ... });して裏で何か処理をやらせといた結果を
後でもしエラーが出ていたら進めちゃいけないタイミングでx.await?;で確認するわけだけど
spawnが返す型をxに律儀に記述するのは面倒なのでそこは略すとして
asyncブロック内で?とOk(())だけ書くとコンパイラが文句を言うので仕方なく記載
0257デフォルトの名無しさん
垢版 |
2021/12/07(火) 21:26:04.18ID:pFZAiCY5
12次元までならiproduct!が使える
use itertools::iproduct;
let r = iproduct!(1..100, 1..100).find(|(x, y)| x * y > 1234);
let r = (|| {
 for (x, y) in iproduct!(1..100, 1..100) {
  if x * y > 1234 {
   return Some((x, y));
  }
 }
 return None;
})();
0258デフォルトの名無しさん
垢版 |
2021/12/08(水) 14:18:48.01ID:6NuoEm2L
ARM版のWindowsでRustのコードを書くのってめんどくさいな
生のWindowsで使用する場合、VisualStudioに付属するx86用のリンカーが非推奨警告を無視すれば使えたものの、次期バージョンからx64専用になってしまうっぽい
一方、仮想環境等+VSCodeでは、RustAnalyzer等が機能せず苦労する・・・・
持ち運び用にケチってMacを買わなかったのが大問題だった、なんかいい方法ないのかな?そもそもARM Windowsで動くリンカーってVisualStudio付属のものしかないのかな?
ケチったって言ってもよくよく考えてみると大して金が浮いてもないし、変なもん買っちまった
0259デフォルトの名無しさん
垢版 |
2021/12/08(水) 14:36:22.94ID:W5vI+s6z
>>258
i686ターゲットのバイナリをバイナリ変換で動かしてるってこと?
aarch64-windowsターゲットとARM用のリンカ使えばネイティブのARMバイナリできるんじゃないかと思うけど
0260デフォルトの名無しさん
垢版 |
2021/12/08(水) 20:15:10.58ID:pzF9gjPk
バイナリバイナリルルルルルー。
0261デフォルトの名無しさん
垢版 |
2021/12/08(水) 21:25:01.32ID:t4Pzut9P
rustはどんどん新しい機能が追加されていくのはいいけど、
後方互換性を気にして過去に追加された「間違った」機能を削除するという
思い切ったこともやって欲しいな

これまでの言語は後方互換性にとらわれて滅茶苦茶になってるから
0265デフォルトの名無しさん
垢版 |
2021/12/09(木) 08:53:14.94ID:sqaPNXyj
>>258
今どきDocker使うのはデフォだから何の問題もない、因みにRustAnalyzerも使える
使えないのは、復数のプロジェクトが見える状態にしてるから
今どき復数ウィンドウ立ち上げても何の問題もない、ルートフォルダを固有にしたら解決
つまり、調査不足が原因
0266デフォルトの名無しさん
垢版 |
2021/12/09(木) 10:59:17.60ID:4q0mFQ+L
ARM は安物のイメージがある。
WSL2, Linux, Docker, VSCode とか使えるのかな?

Mac も、M1 に変わったから
0267デフォルトの名無しさん
垢版 |
2021/12/09(木) 11:10:00.09ID:XwSSuf4e
原理的には ARM のほうがインテル系 (もはや AMD 系と呼ぶべきか) よりも高速化できる可能性があるとは言われている。
今以上に回路を細かくするのは無理というところまできてしまっているのでアーキテクチャのほうで見直しが必要なんだが
インテル系は互換性が足かせになってしまっていてあまり思い切ったことが出来ない。

現時点はインテル系向けにチューニングされたソフトウェア資産が多いから上手くいっているけど将来もそうとは限らない。
0269デフォルトの名無しさん
垢版 |
2021/12/09(木) 14:22:31.39ID:RSXecyhf
CISCRISCの話じゃなくてメモリモデルの話ならそうかなって思う
今のx64って実質中身RISCって聞いたことあるし
Rustで言うとx64では全部SeqCstとして扱われるみたいな話
0270デフォルトの名無しさん
垢版 |
2021/12/09(木) 17:42:03.96ID:VJ9QB09P
リソースの話だけなら命令デコーダーとか?
x86_64は拡張や互換性とか可変長命令だったりで無駄にトランジスタ消費するのが電力性能比的に足かせみたいな
0271デフォルトの名無しさん
垢版 |
2021/12/09(木) 20:39:08.00ID:0MvTGuxY
今どきのプロセッサだと分岐予測器やキャッシュが支配的でデコーダなんて誤差だと思う
あと可変長は命令側の帯域やキャッシュ効率が良くなるという面もあってRISC系でも採用してることが多い
結局両者とも長年の改善で似たようなとこに落ち着いてるわけで、ISAが違うからどうこうみたいな話は結構眉唾
0272デフォルトの名無しさん
垢版 |
2021/12/11(土) 19:08:58.23ID:oic9EtmK
こういうことをしたいのですがコンパイルエラーとなってしまいます
const DEFAULT_NAME: &str = "namae";
let arg1: Option<String> = std::env::args().nth(1);
let name: &str = arg1.map_or(DEFAULT_NAME, |s| s.as_str());
どう直せばよいでしょうか?
0273デフォルトの名無しさん
垢版 |
2021/12/11(土) 19:10:55.89ID:ZSpAs+oG
namaeじゃなくてnameな
aが余計
この程度の英語のスペル書けないとかプログラミング向いていないしやめた方がいいよ
0275デフォルトの名無しさん
垢版 |
2021/12/11(土) 19:35:01.57ID:K+rsGRUk
>>272
そのままだとarg1が消費されてなくなるのに参照だけ残ることになるからエラー
Stringで受ければいいよ
let name: String = arg1.unwrap_or(DEFAULT_NAME.to_string());
0278デフォルトの名無しさん
垢版 |
2021/12/11(土) 20:29:51.18ID:/anFx7me
>>275
これだとarg1がSomeの時もto_string()が呼び出されて無駄なヒープアロケーションが走るのでunwrap_or_elseにすべき
0279デフォルトの名無しさん
垢版 |
2021/12/11(土) 22:35:07.46ID:oic9EtmK
みなさんありがとうございます
Stringにする方法は無事にこれで動きました
let name: String = arg1.unwrap_or_else(|| DEFAULT_NAME.to_string());
元の質問>>272のように&strにする方法は無いのでしょうか?
もし可能ならばto_string()のヒープアロケーションを減らせるかなという質問です
0281デフォルトの名無しさん
垢版 |
2021/12/11(土) 23:20:49.43ID:yVS9OnV5
場合によってはこれでもいいのかな?
let name: &str = &arg1.as_ref().map_or(DEFAULT_NAME, |s| s.as_str());
0282デフォルトの名無しさん
垢版 |
2021/12/11(土) 23:54:40.62ID:tYxQqCnY
>>281
それでもよいけど正解はシンプルなこれ
let name: &str = if let Some(ref arg1) = arg1 { arg1 } else { DEFAULT_NAME };
まずarg1を消費しないようにrefで受ける
2代目のarg1は&Stringなので自動的に&strへderefされる
0283デフォルトの名無しさん
垢版 |
2021/12/12(日) 02:10:02.51ID:h/Sb7JBW
1.40からas_derefっつうのがあるんだってさ
let name = arg1.as_deref().unwrap_or(DEFAULT_NAME);

でもコマンドライン引数の場合は消費しないメリットがほぼ無いのでCowのほうがいいかな
0284デフォルトの名無しさん
垢版 |
2021/12/12(日) 04:28:54.46ID:8d+idsXS
どの型で統一すべきかは
(1) その後に加工伸長などするならString (arg1をここで&strに統一するのは無駄)
(2) 参照するのみなら&str (DEFAULT_NAMEをここでto_stringするのは無駄)
(3) その後に判明する条件次第で両ケースありうるならCow (ただし常にCow利用はCowコストが無駄)
って感じ?
0285デフォルトの名無しさん
垢版 |
2021/12/12(日) 10:07:32.08ID:svMJrknn
おそらくその通りだけど、CLIツールの初回一回だけのアロケーションにそこまでこだわるのがそもそも無駄って気もする
ループ内とかでもなければ雑にString作っちゃっていいかもね
0287デフォルトの名無しさん
垢版 |
2021/12/12(日) 10:46:59.45ID:8d+idsXS
>>285
今回のケースはそうだね
ただしヒープ割り当てをなるべく避ける様々な手法を把握しているか否かは色んな局面で効いてくるから
今回6通りも動くコード例が示されたことは多様に対応可能な柔軟性の良さかな
気にしなくても書けるし気にすれば効率を上げることができる点で
0288デフォルトの名無しさん
垢版 |
2021/12/12(日) 18:38:25.33ID:h/Sb7JBW
>>284
Cowと&strに揃える場合の一番の違いはライフタイム管理
Stringを&strにするとライフタイム管理がつきまとうから
すぐ使いきる場合以外はCowに比べてメンテナンスしにくいコードになる
0289デフォルトの名無しさん
垢版 |
2021/12/12(日) 18:59:43.58ID:3rjDzGgS
文字列についてはStringにするかCow<str>にするか迷うくらいならinternしちゃうのも手かと
どのライブラリが定番なのかよく知らないけど
0290デフォルトの名無しさん
垢版 |
2021/12/12(日) 19:49:57.76ID:be4Z/veb
>>281
> let name: &str = &arg1.as_ref().map_or(DEFAULT_NAME, |s| s.as_str());

それarg1の前の&は不要でこれで動く
let name: &str = arg1.as_ref().map_or(DEFAULT_NAME, |s| s.as_str());

さらにas_str()使うより短く書けて&**sで&strになる
let name: &str = arg1.as_ref().map_or(DEFAULT_NAME, |s| &**s);

さらに&Stringのsのままでもderefされるため大丈夫
let name: &str = arg1.as_ref().map_or(DEFAULT_NAME, |s| s);

クロージャが何もしてないからといって無くしてしまうとderefが効かず型不一致コンパイルエラー
× let name: &str = arg1.as_ref().unwrap_or(DEFAULT_NAME);

そこで明示的にderefしてやればよい
let name: &str = arg1.as_deref().unwrap_or(DEFAULT_NAME);
0291デフォルトの名無しさん
垢版 |
2021/12/13(月) 21:23:25.03ID:zBnuOauJ
ken okabeのqiitaの記事がまた炎上してるよ
mod_poppoにボコボコにされてる
0293デフォルトの名無しさん
垢版 |
2021/12/13(月) 23:00:30.90ID:Yx06Lw1d
ググってもよくわからないのですが、どういった方なんですか?
0295デフォルトの名無しさん
垢版 |
2021/12/13(月) 23:59:51.20ID:mqpFvLOG
>>291
poppoとかいうやつも多様な定義や多様な解釈が存在している中で不要なイチャモンばかりだな
さらに冒頭のこれも

> JavaScriptで演算子オーバーロードを実現しようとするのは筋が悪い

たまたま例としてJavaScriptを用いているだけなのにそれすら理解できていない
okabeは使用言語と無関係に成り立つ話をしてるだろ

> reduceは二項演算ではなく三項演算として捉えるべき

これも些細なことであって例えばRustなら
fold()は『入力列・初期値・演算関数』の三項演算だけど
reduce()は『入力列・(初期値は入力列の先頭なので無指定)・演算関数』の二項演算

とはいえokabeの方もイテレータすら扱っていないからイマイチ
0297デフォルトの名無しさん
垢版 |
2021/12/14(火) 10:41:11.49ID:QBQJlKEt
P2P方式の2D対戦ゲームを作りたいと考えています。
おすすめのゲームエンジンやライブラリはございますか?
0298デフォルトの名無しさん
垢版 |
2021/12/14(火) 11:46:02.04ID:mpAOsF0a
>>297
あくまでゲームを作ることが目的なんだったら普通にUnityとかでいいんじゃない?
どうしてもRust使いたいならサーバー側で使えばいい
0299デフォルトの名無しさん
垢版 |
2021/12/14(火) 12:45:44.37ID:QBQJlKEt
>>298
個人的にRustが好きなので技術向上のためにもRustで作りたいと考えています。
現在はAmethystとlibp2pを用いて開発しようと考えているのですが、如何せん知識が浅くこれで目的のものが作れるのか分かりません。
是非先人の知恵をお貸しください。
Rustでの開発にロミオとジュリエットの恋ほどの壁があるという場合は、大人しくC++かUnityで作成します・・・
0300デフォルトの名無しさん
垢版 |
2021/12/14(火) 13:10:49.68ID:+JRF3Q+g
そんだけの情報ではなんともいえん。

見通しが立たないものを試行錯誤で作る場合には
モジュールではなくレイヤで分割したほうがいいという考え方がある。
要するに機能不足でもバグだらけでもコードが整理されてなくてもいいからとにかく「動くもの」を作って
その上に足りないものをどんどん足していくという方法論だ。

よくわかってないなら小さいもので色々やってみて知識を積み重ねるべきで、
よくわからんまま目的に向かって邁進してもあんまり技術向上にはならんよ。
0301デフォルトの名無しさん
垢版 |
2021/12/14(火) 13:22:32.10ID:QBQJlKEt
>>300
ありがとうございます
色々試してみます
0302デフォルトの名無しさん
垢版 |
2021/12/14(火) 13:53:41.90ID:ZTFSAiNI
>>299
Amethystは開発中止になったから今からやるのは微妙かも
gamedev.rsに今アクティブなエンジンやゲームがスクショ付きで載ってるから
そこからイメージにあうものを探すといいかもしれない
0303デフォルトの名無しさん
垢版 |
2021/12/14(火) 15:30:19.02ID:QBQJlKEt
>>302
そうだったんですね・・・
時間は掛かるかもしれませんが、色んなものを試して自分に合う物を探すことにします
0304デフォルトの名無しさん
垢版 |
2021/12/15(水) 07:48:40.06ID:inpCEPk8
技術を高める目的なら windows-rs や wgpu-rs みたいな一段下から積み上げるのも楽しいよ。

ゲーム作る道のりは遠くなるけど、画面に三角形出したり、キーの入力受け付けたりするだけで達成感が出てくる。
0306デフォルトの名無しさん
垢版 |
2021/12/17(金) 16:39:33.05ID:6JlgT7vi
既出だったらすいません
前から疑問だったのですが、出力におけるprint!マクロのような入力用マクロが標準ライブラリに用意されていない理由ってなんですか?
0309デフォルトの名無しさん
垢版 |
2021/12/17(金) 23:52:56.58ID:6JlgT7vi
>>308
熟読させていただきました。
私としてはたった数十行のコードであること且つ他のほとんどの言語に存在しているものなのであっても良いのかなと思ったのですが、Rustの基本理念を考えると慎重になる理由も理解出来ました。
Rustの経験が浅い私目線ではあまり腑に落ちませんでしたが、皆さんはどう考えていますか?
0310デフォルトの名無しさん
垢版 |
2021/12/18(土) 15:05:52.37ID:JzdvFl4u
熟読はしてないけど、外部ライブラリで簡単に実現可能であるなら
直感的には、本体メンテナの苦労を増やすほど価値があると思えないし別にいらんかな

こういうIOとかCLIプロンプトらへんの機能ってどうしても好みが分かれるというか、
ユースケースによって必要な機能がかなり違ってきちゃうと思うし
0312デフォルトの名無しさん
垢版 |
2021/12/18(土) 23:17:58.09ID:SfwydFh9
>>306
C言語でのprintf相当はあるのにscanf相当がstdにないのはなぜか?ですね
逆になぜprintf相当がRustの標準ライブラリにあるのか?を考えてみると

(1) 読み書きの非対称性
人間が読むためにプログラムが書くことはエラー表示を含めて利用必須かつ頻出
一方で人間が書いたものをプログラムが読むことはレア
ファイルや通信相手への読み書きは各プロトコル/各API/シリアライズ等で対象外

(2) コンパイラサポート
print!やformat!等は頻出するので効率面からコンパイラサポートが効率的
実際にそれらが利用しているformat_args!はコンパイラ内蔵マクロ

(3) 標準ライブラリ採用
外部ライブラリで実現可能なものは採用しないが基本
今回はコンパイラ内蔵マクロだから採用

つまり出力は頻度と効率化で採用がクリアされたけど
入力は外部ライブラリで十分かなと
0313デフォルトの名無しさん
垢版 |
2021/12/19(日) 02:25:28.05ID:KXG/wmTu
しかし競プロでみんなproconioとかいう謎の専用ライブラリ使ってるの見た目悪すぎて笑える
0314デフォルトの名無しさん
垢版 |
2021/12/19(日) 04:21:35.56ID:1R2jF/rb
競プロ全然知らないけどstdinに入力数値がくるからか

| 入力は以下の形式で標準入力から数値が与えられる。
| a b c d e
| 積が奇数なら Odd と、 偶数なら Even と出力せよ。

標準ライブラリだけ使うと毎回こんなの書くのは面倒だもんな

| use std::io::{stdin, BufRead, BufReader};
| println!("{}", if BufReader::new(stdin()).lines().next().unwrap().unwrap().split(' ').any(|s| s.parse::<isize>().unwrap() & 1 == 0) { "Even" } else { "Odd" });

>>313
そのproconioを使うとこうなるようだ

| proconio::input! { v: [isize; 5] }
| println!("{}", if v.into_iter().any(|n| n & 1 == 0) { "Even" } else { "Odd" });
0317デフォルトの名無しさん
垢版 |
2021/12/19(日) 08:28:47.39ID:KXG/wmTu
>>316
あいやごめん。proconioのところはどうあがいてもプロコン専用のproconioが一番見やすいよ。それ用に特化されたライブラリだし
俺が大好きかよって言ったのは
println!("{}", if v.into_iter().any(|n| n & 1 == 0) { "Even" } else { "Odd" });
の部分
0320デフォルトの名無しさん
垢版 |
2021/12/19(日) 09:42:08.31ID:1R2jF/rb
これでいいかね?
println!("{}", if v.into_iter().any(|n| n & 1 == 0) {
 "Even"
} else {
 "Odd"
});
0321デフォルトの名無しさん
垢版 |
2021/12/19(日) 09:57:56.98ID:KXG/wmTu
俺ならこんな感じかなあ
俺は頭悪いから、途中結果に一つ一つ名前つけないとわかんなくなっちゃうわ
まあワンライナー見た時に「グエー」って思っただけだからごめん。「大好きかよ」とかいっておいてなんだけどあんま気にしないで

use proconio::input;

fn main() {
input!(v: [usize; 5]);
let is_even = v.iter().any(|x| x % 2 == 0);
let result = if is_even {
"Even"
} else {
"Odd"
};
println!("{}", result);
}
0322デフォルトの名無しさん
垢版 |
2021/12/19(日) 10:13:36.41ID:1R2jF/rb
>>321
なるほど
じゃあ最初の標準ライブラリのみはどのように分けるのかな
println!("{}", if BufReader::new(stdin()).lines().next().unwrap().unwrap().split(' ').any(|s| s.parse::<isize>().unwrap() & 1 == 0) { "Even" } else { "Odd" });
0323デフォルトの名無しさん
垢版 |
2021/12/19(日) 10:17:01.07ID:KXG/wmTu
>>322
proconio使うw
Rustで競プロするにはIOごときに専用ライブラリ使うことになってなんかなあって思うけど、そう思いながら使う
0324デフォルトの名無しさん
垢版 |
2021/12/19(日) 12:54:53.29ID:XhCh7cuL
>>315
ワンライナーやクロージャでまとめて書くと所有権やライフタイムの問題が出にくいんだよ
他の言語と違ってRustで適切に分割して読みやすく書くのは初心者には難しい
0327デフォルトの名無しさん
垢版 |
2021/12/19(日) 21:36:12.89ID:1R2jF/rb
>>326
println全体が改行されてしまった

println!(
 "{}",
 if BufReader::new(stdin())
  .lines()
  .next()
  .unwrap()
  .unwrap()
  .split(' ')
  .any(|s| s.parse::<isize>().unwrap() & 1 == 0)
 {
  "Even"
 } else {
  "Odd"
 }
);

一方で分割するとこうなった

let cond = BufReader::new(stdin())
 .lines()
 .next()
 .unwrap()
 .unwrap()
 .split(' ')
 .any(|s| s.parse::<isize>().unwrap() & 1 == 0);
println!("{}", if cond { "Even" } else { "Odd" });

if式自体はワンライナーーで正解とrustfmtはおっしゃってる
0329デフォルトの名無しさん
垢版 |
2021/12/19(日) 22:05:50.34ID:1R2jF/rb
例えば>>321がif式を5行に分割しているが
それもrustfmtにより1行に修正された

Rust標準ライブラリのソースでもワンライナー
bool.rs: if self { Some(t) } else { None }
result.rs: let n = if self.inner.is_some() { 1 } else { 0 };
time.rs: let prefix = if f.sign_plus() { "+" } else { "" };

>>328
では何の話かね?
0331デフォルトの名無しさん
垢版 |
2021/12/19(日) 23:10:30.41ID:ZhiL7Huf
心底どうでもいい。
保守性に貢献するどころかマイナスになるようなクソプライドコードの導入すんなよ。
0334デフォルトの名無しさん
垢版 |
2021/12/19(日) 23:25:17.24ID:/BRS7QS/
区別できなかったからrustfmtを持ち出したんやろ
どこに改行入れるべきかって話だと思ったんだろなww
0335デフォルトの名無しさん
垢版 |
2021/12/19(日) 23:41:46.15ID:1R2jF/rb
rustfmtを持ち出したのは俺じゃないぜ
あと今回のケースならここは分割するよな
let reader = BufReader::new(stdin());
let line = reader.lines().next().unwrap().unwrap();
let is_even = line.split(' ').any(|s| s.parse::<isize>().unwrap() & 1 == 0);
0337デフォルトの名無しさん
垢版 |
2021/12/19(日) 23:59:56.43ID:cDs+Q4pL
問題文が>>314でこうなってるから
>> | 入力は以下の形式で標準入力から数値が与えられる。
>> | a b c d e

if let [a, b, c, d, e] = line
 .splitn(5, ' ')
 .map(|s| s.parse::<isize>().unwrap())
 .collect::<ArrayVec<_, 5>>()[..] {

あとこれでいい
let is_even = a & b & c & d & e & 1 == 0;
0338デフォルトの名無しさん
垢版 |
2021/12/20(月) 05:23:59.31ID:XPDM+Al+
そういえばいつの間にか
let variable = 3;
println!("{variable}");
みたいな書き方が出来るんだけどこれ前からだっけ?
0343デフォルトの名無しさん
垢版 |
2021/12/20(月) 19:04:29.92ID:MpI5dMic
間違っているコードは出ていないような
問題視してる人は具体的に何を問題にしているの?
0345デフォルトの名無しさん
垢版 |
2021/12/21(火) 11:25:19.41ID:TTfv6HaA
https://doc.rust-jp.rs/book-ja/ch18-03-pattern-syntax.html#%E3%83%9E%E3%83%83%E3%83%81%E3%82%AC%E3%83%BC%E3%83%89%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%AE%E6%9D%A1%E4%BB%B6%E5%BC%8F
ここの最後のところに

パターンと関わるマッチガードの優先度は、以下のように振る舞います:
(4 | 5 | 6) if y => ...
以下のようにではありません:
4 | 5 | (6 if y) => ...

とあるんですが、後者のようになってほしい場合は4|5と6 if yを別々に書くしか無いですか?
0348デフォルトの名無しさん
垢版 |
2021/12/22(水) 22:58:00.27ID:mfli1g17
> しかし競プロでみんなproconioとかいう謎の専用ライブラリ使ってるの見た目悪すぎて笑える
いや、ほぼ公認のクレートなんだが・・・
謎の専用ライブラリとかいってる時点で、お察しか?

あと、見た目悪いってどういうことなんかね
includeしたら見た目悪すぎなわけ?
0349デフォルトの名無しさん
垢版 |
2021/12/22(水) 23:53:48.10ID:Wk3NOZd2
Rust bookの以下の記述について質問です

https://doc.rust-jp.rs/book-ja/ch19-05-advanced-functions-and-closures.html#クロージャを返却する
> 以下のコードは、クロージャを直接返そうとしていますが、コンパイルできません:
>
> fn returns_closure() -> Fn(i32) -> i32 {
> |x| x + 1
> }
> コンパイラには、クロージャを格納するのに必要なスペースがどれくらいかわからないのです。
> この問題の解決策は先ほど見かけました。
>
> fn returns_closure() -> Box<Fn(i32) -> i32> {
> Box::new(|x| x + 1)
> }

とBox化しなさいと書かれているのですが
以下のようにimplを付けるとBoxを使わなくてもコンパイルが通り動きました

fn make_closure_add1() -> impl Fn(i32) -> i32 {
|x| x + 1
}

このimpl付加は暗に自動的にBox化されているということなのでしょうか?
0352デフォルトの名無しさん
垢版 |
2021/12/23(木) 15:17:54.33ID:BEeWZFks
>>342
逆だ、コードは常に「正解」で動いていて「間違い」ない。

あんたの書いたバグもコンピューターにとっては一部の隙もなく正解であり、書かれたその通りに動き、無慈悲である。
同じ目的で、多数、あるいは二人の人が書いたコードで違いが出るのは「表現の違い」であり「間違い」と決めつける
のは人間の主観や嗜好でしかなく、仮にコードへ正誤を求めるなら明確に表現できていなればならず、矛盾が生じる
0355デフォルトの名無しさん
垢版 |
2021/12/23(木) 18:55:13.24ID:TD851Muu
”動いていて”と言っているからコンパイルは通ってる前提だろう、”コードへ正誤を求める”といっているから
仮にコンパイルが通らないコードは明確にそれ(誤り・間違い)が表現できている
ポエミーなのはその通りだろう
0356デフォルトの名無しさん
垢版 |
2021/12/23(木) 21:22:53.78ID:NwYcCv97
>>349
Boxとはヒープを使うということです
Rustではコードで明示的に指定しない限り勝手にヒープが使われることはないです
(もちろんBox以外にもVecやStringなどヒープを使うものを使ってもそれは明示的に指定したことになります)

その Box<Fn(i32) -> i32> は今は Box<dyn Fn(i32) -> i32> と書く必要があります
では本題の impl Fn(i32) -> i32 と書いた場合はどうなるのでしょうか?
以下のように3種類のクロージャを作ってサイズや型を表示させてみると
fn main() {
 let direct_closure = |x: i32| x + 1;
 let impl_closure = make_impl_closure();
 let box_closure = make_box_closure();
 println!("{} {}", std::mem::size_of_val(&direct_closure), type_of(&direct_closure));
 println!("{} {}", std::mem::size_of_val(&impl_closure), type_of(&impl_closure));
 println!("{} {}", std::mem::size_of_val(&box_closure), type_of(&box_closure));
}
fn make_impl_closure() -> impl Fn(i32) -> i32 {
 |x| x + 1
}
fn make_box_closure() -> Box<dyn Fn(i32) -> i32> {
 Box::new(|x| x + 1)
}
fn type_of<T>(_: &T) -> &'static str {
 std::any::type_name::<T>()
}

実行結果は以下のように表示されます
0 tmp::main::{{closure}}
0 tmp::make_impl_closure::{{closure}}
16 alloc::boxed::Box<dyn core::ops::function::Fn<(i32,)>+Output = i32>
つまりimplでは直接クロージャ指定したのと全く同じです
(上記では定義した関数名だけが異なる)
0358デフォルトの名無しさん
垢版 |
2021/12/23(木) 22:34:57.88ID:NwYcCv97
では常に impl を使えばよいのかというと
以下のような条件によって異なるクロージャを返す時
ここで Box を使わず impl Fn(i32) -> i32 にしようとすると
2つのクロージャの型が違うとコンパイラに怒られます

fn make_closure(curry: Option<i32>) -> Box<dyn Fn(i32) -> i32> {
 if let Some(curry) = curry {
  Box::new(move |x| x + curry)
 } else {
  Box::new(|x| x + 1)
 }
}

結局クロージャでない場合と同じ話で
同じトレイトでも型が異なるものが同居する時にBox化します
>>349のRust bookの例はBox化が不要なケースでBox化だから混乱しますね
0359デフォルトの名無しさん
垢版 |
2021/12/24(金) 11:53:17.86ID:8qqh3vKr
コンパイル通ってれば全て正解とかバカ丸出し。
厳密な定義でも使えない定義があるってことすら理解してなさそう。
0360デフォルトの名無しさん
垢版 |
2021/12/24(金) 12:05:46.49ID:0hdsBqvb
型安全だったらコンパイル通れば実行時エラーにならないという点で全て正解っていうのは別に間違ってないと思うけど?
これにケチつけるのは流石にどうかと
0362デフォルトの名無しさん
垢版 |
2021/12/24(金) 15:42:15.21ID:8qqh3vKr
>>360
実行時エラーにならないなんて最低限のところだっつーの。だからバカだっていうんだよ。
0363デフォルトの名無しさん
垢版 |
2021/12/24(金) 16:05:46.66ID:GD01KKAb
もしかしてrustはlinuxに取り込まれるわけねーだろって言い張っていた人?
予言外していたよね。お疲れ様です。
0365デフォルトの名無しさん
垢版 |
2021/12/24(金) 16:10:39.10ID:GD01KKAb
なんか草
0366デフォルトの名無しさん
垢版 |
2021/12/24(金) 16:20:12.59ID:GD01KKAb
25 デフォルトの名無しさん sage 2021/04/27(火) 08:00:23.09 ID:/+bIFNU8
>>23
あのね。。書けばそうなるってものじゃなくてそれを実装しなきゃならんのよ。。
コンパイラにそういったコンテクストを判断させるのがめちゃくちゃ難しいっていってるでしょ?
なんでそんなに読み取れないの?

27 デフォルトの名無しさん sage 2021/04/27(火) 16:10:45.63 ID:/+bIFNU8
>>26
だからそのコードじゃpanic捉えきれねーからカーネルに入れるわけねーだろって
言ってんじゃん。。何読んでんだよ。

28 デフォルトの名無しさん sage 2021/04/27(火) 18:23:48.67 ID:n/AWrch2
まあ半年後どうなるかで誰が正しかったかは分かるわな

29 デフォルトの名無しさん sage 2021/04/27(火) 20:32:29.92 ID:/+bIFNU8
半年も経たなくてももうわかってるっつーの。。だからちゃんと英語の勉強しましょうね。

完全に同一人物だよね
0367デフォルトの名無しさん
垢版 |
2021/12/24(金) 16:26:02.78ID:GD01KKAb
https://lkml.org/lkml/2021/12/6/461

英語読めんならこれになんて書かれているのかわかるよね?
0368デフォルトの名無しさん
垢版 |
2021/12/24(金) 16:31:02.04ID:GD01KKAb
予想が完全に外れたID:8qqh3vKrを晒し上げ♪♪♪
ここまで簡単な予想を外すとかバカ過ぎて生きていけなさそうwww
馬鹿丸出しですねwwwwww
0369デフォルトの名無しさん
垢版 |
2021/12/24(金) 16:40:31.03ID:8qqh3vKr
素でバカなんだな。。もうコンパイル通ったんで俺の仕事終わりとか現場で言ってろよ。。話にもならん。
0370デフォルトの名無しさん
垢版 |
2021/12/24(金) 16:42:14.31ID:/xk3NPni
>>362
最低限の性質を満たしている⇔正解って言ってんじゃん。。何読んでんだよ。
なんでそんなに読み取れないの?
だからバカだっていうんだよ。
だからちゃんと日本語の勉強しましょうね。
0371デフォルトの名無しさん
垢版 |
2021/12/24(金) 16:45:16.93ID:/xk3NPni
>>369
なお予言を外したことについては一貫してノータッチwwwww
話をしたくないのは君だよねwwwwww
0372デフォルトの名無しさん
垢版 |
2021/12/24(金) 16:46:19.44ID:/xk3NPni
>>369
同一人物だってことはバレバレだっつーの。バカ丸出し。wwwwwwwwww
0374デフォルトの名無しさん
垢版 |
2021/12/24(金) 17:38:56.03ID:8qNIErj3
厳密な定義でも使えない定義?Rustに特定条件下でCのような未定義になる動作あったっけ?
0375デフォルトの名無しさん
垢版 |
2021/12/24(金) 18:41:11.93ID:759ZBatD
スレの文脈はしらんけど、
Rustではunsafeを使ってなければコンパイラが、未定義動作が起きないということや、データ競合がないことを保証をしてくれるよ
0376デフォルトの名無しさん
垢版 |
2021/12/24(金) 19:10:24.57ID:/xk3NPni
>>369
予言外れましたよね?wwwwwwww
0378デフォルトの名無しさん
垢版 |
2021/12/26(日) 12:56:45.57ID:NwCcamJz
Rustの勉強を昨日から開始した。後は構造体とかかな。
0380デフォルトの名無しさん
垢版 |
2021/12/26(日) 19:27:36.42ID:IL2U4vJU
Rustはこう謳っている
>なぜRustか?
>パフォーマンス
>信頼性
>生産性
真っ向から反するコードを貼ってりゃゴミ・クソ言われて当然なんだよなぁ
0381デフォルトの名無しさん
垢版 |
2021/12/26(日) 19:29:23.79ID:Haex5ds9
すまんが、配列に入った数値の平均ってパッと出せないもんなの?
他言語でふにゃふにゃになった俺の頭でコードを書いたら、桁の溢れとか精度とか酷えことになりそう・・・・
0384デフォルトの名無しさん
垢版 |
2021/12/26(日) 22:30:25.75ID:L9HJqboW
>>381
普通に平均を求めるだけではダメなのでしょうか?

fn main() {
assert_eq!(5.5, (1..=10).average());
assert_eq!(6.8, [2.3, 8.7, 9.4].average());
}

use num::ToPrimitive;
trait Average {
fn average(self) -> f64;
}
impl<I> Average for I
where I: IntoIterator, <I as IntoIterator>::Item: ToPrimitive,
{
fn average(self: I) -> f64 {
self.into_iter().fold((0.0, 1.0), |(ave, size), n| (ave + (n.to_f64().unwrap() - ave) / size, size + 1.0)).0
}
}
0389デフォルトの名無しさん
垢版 |
2021/12/27(月) 12:32:52.22ID:OyINMfYQ
ここの人たちってplaygroundとかなんで完全に動かせるコードで提示しないんだろ・・・?
アドバイス貰うにも回答するにも一生懸命スペース全角置換したり、まじ両方キモイw
trait Averagewwwww
0391デフォルトの名無しさん
垢版 |
2021/12/27(月) 14:19:38.18ID:Btn3kp2t
普通の関数にすべきかどうかはメソッドチェーンにしたいかどうかで判断すればよろしい
0392デフォルトの名無しさん
垢版 |
2021/12/27(月) 14:43:10.42ID:0vghZEjd
>>389
playgroundでは自己顕示欲が満たせないんだよw

まあplaygroundでは動かせないコードもあるけどな
0393デフォルトの名無しさん
垢版 |
2021/12/27(月) 15:03:42.29ID:6JVZDUUj
>>381
こういう子は、移動平均出したくなった時とかどうすんだろ…
愚直に毎回平均出す関数とか使っちゃうわけ?
0396デフォルトの名無しさん
垢版 |
2021/12/27(月) 21:53:06.04ID:N7w3YVE+
>>384
それだと桁溢れは防止できているが誤差蓄積の対処ができていない
もう一つパラメタを増やしてこうしたほうがいい
fn average(self: I) -> f64 {
self.into_iter().fold((0.0, 1.0, 0.0), |(ave, size, fix), n| {
let diff = (n.to_f64().unwrap() - ave) / size - fix;
let new_ave = ave + diff;
(new_ave, size + 1.0, (new_ave - ave) - diff)
}).0
}

>>387
イテレータメソッド化するにはそのためのtrait宣言が必須
もしわからないならitertoolsなどのイテレータ拡張ライブラリを見よう

>>389
標準ライブラリのsum()がtrait Sumを使っているからtrait Averageでもまあいいとは思う
ただし今回はイテレータメソッド拡張のみに用いているようだからtrait IteratorExtなどの命名がわかりやすいとは思う
0399デフォルトの名無しさん
垢版 |
2021/12/27(月) 22:15:24.91ID:N7w3YVE+
>>398
標準ライブラリにおいてsum()やproduct()
それを一般化したfold()やreduce()
さらにmax()やmin()など当然イテレータメソッドになっている
むしろ今回のaverage()だけをイテレータメソッドにしない理由が見当たらない
0402デフォルトの名無しさん
垢版 |
2021/12/27(月) 22:31:56.63ID:/o/Y1bP3
>>400
入力型と出力型で大量の組み合わせ(例:i32→f32)が用途に応じて要求されるのと
単純に合計をサイズで割った平均でよい用途もあれば
件数が多いと合計がオーバーフローするからその対策が欲しい用途もあれば
桁が大きく異なるデータ列の場合に浮動小数点の誤差改善が欲しい用途など多岐にわたる
だから平均を標準ライブラリで何か一つ用意は無理
0403デフォルトの名無しさん
垢版 |
2021/12/27(月) 22:51:58.74ID:Btn3kp2t
単にこれまで標準ライブラリに入れようとした人がいなかったか
そういう人はいたが必要性を説得できなかっただけでしょう
sumやproductに比べるとユースケース限られるしね
0405デフォルトの名無しさん
垢版 |
2021/12/28(火) 00:10:56.21ID:THzUMFur
「件数が多いと合計がオーバーフローするからその対策が欲しい用途」そんな考えがオカシイ
sumですらオーバーフローに言及しているだけで対策が欲しいから、だからstdじゃないという理由では無い
https://doc.rust-lang.org/std/iter/trait.Iterator.html#panics-3
When calling sum() and a primitive integer type is being returned, this method will panic if the computation overflows and debug assertions are enabled.

必要性を説得出来ないだけというのが正しい。浮動小数の加減算による誤差蓄積だって、浮動小数を扱うなら当然起こることだが
誤差改善が欲しい用途があるからstdじゃないとか嘘ばっかり言わないで?おまえさ、迷惑だからRust辞めてくれよ?
最小限、分かったふりで糞まき散らすな?
0406デフォルトの名無しさん
垢版 |
2021/12/28(火) 00:45:10.69ID:vzPVHyZI
>>405
それは君が無知
平均算出にはsumを求めずとも差分を逐次的に適用するアルゴリズムがあるoverflowを回避する対策で一般的に使われている
例えば>>383のstatsもその方法で平均を算出している
sumの例を出すのは見当違い
0407デフォルトの名無しさん
垢版 |
2021/12/28(火) 00:52:41.14ID:We8KhoPF
>>406
アルゴリズムの話じゃなくてstdに入ってない理由の説明がおかしいという指摘だと思うよ
言葉汚いし何言ってるかわかりづらいけど
0410デフォルトの名無しさん
垢版 |
2021/12/28(火) 02:00:22.76ID:We8KhoPF
>>409
途中で書き込んでしまった

そもそもaverageか類似の関数をstdに取り込む議論が過去にあったならそれをポイントしてほしい
0411デフォルトの名無しさん
垢版 |
2021/12/28(火) 02:37:31.31ID:vzPVHyZI
多数あり外部で十分派なのでそこは興味ない
sortは2種類しかなく2種類とも標準ライブラリでサポートしている
0413デフォルトの名無しさん
垢版 |
2021/12/28(火) 10:24:44.25ID:ZpntEDp9
外部で十分と言えば、cratesは先着順で名前取れるからこの先優良ライブラリ程クソみたいな名前になっていくよね
0415デフォルトの名無しさん
垢版 |
2021/12/28(火) 11:15:50.74ID:ZpntEDp9
ライブラリの永続性を保つのに名前でマッチさせるのやめてUUIDかハッシュか何かでマッチさせれば良かったのにみたいな気持ちはある
0416デフォルトの名無しさん
垢版 |
2021/12/28(火) 11:32:06.72ID:HJMjm+0C
>>414
横から失礼。
個人的にはそもそもcrate.io に頼るのがあまり好きでないなと。
Rust に限らない話だけど、こういった中央集権的なリポジトリを用意すること自体が名前争奪戦の元になるのではないかなと。
それぞれのWEBサイトで勝手に配布すればいいのにってね。
バージョン管理方法の方法論なんかも関わるから簡単な事ではないんだろうけど。
0417デフォルトの名無しさん
垢版 |
2021/12/28(火) 11:35:30.26ID:QBGkL4gv
現状でもGitHubから直接落としてくることも出来るけど、GotHubのリポジトリは消せてしまうからな
0418デフォルトの名無しさん
垢版 |
2021/12/28(火) 13:40:51.12ID:XD/wAJcN
cargo updateでマイナーバージョンアップやらせるのも規約決めたり工夫ご必要だし
専用のリポジトリ用意する方がわかりやすくはあるような
crates.io以外にも複数のリポジトリを混在して使えるようにできれば良いのかな
0419デフォルトの名無しさん
垢版 |
2021/12/28(火) 14:10:43.98ID:Qs/YVt0a
cargoはどこからでも落とせる
crates.ioなみに安全性、信頼性、永続性が確保できるんなら好きにすればいい
0420デフォルトの名無しさん
垢版 |
2021/12/28(火) 14:45:21.34ID:ZpntEDp9
永続性を謳うサービスで名前で管理したらそりゃあいい名前の取り合いになるよなあ
0422デフォルトの名無しさん
垢版 |
2021/12/28(火) 15:16:22.59ID:c9bIiubz
GoみたいにGithubがデファクトスタンダードなレジストリになっても一覧性の面で不便だし、crates.ioでいいと思うけどなあ
0425デフォルトの名無しさん
垢版 |
2021/12/28(火) 22:07:01.63ID:a7HoB6QX
ぼぼぼ、ぼくちんのために誰か優秀なaverage()をおながいします
0435デフォルトの名無しさん
垢版 |
2022/01/02(日) 14:53:21.62ID:3FXnOBLq
高度IT人材、富士通は最大年収3500万円へ

「富士通年収3500万!」日本のIT企業の年収も、高額化してきました

AI人材の獲得に超本気 NECが新人事制度を9人に適用、富士通は最大年収3500万円へ

【年収3500万円も】富士通、「ジョブ型」人事制度を導入 幹部社員から 高度IT人材

来年度から副業解禁 人材多様化へ―大同生命次期社長

第一生命HD、副業解禁 約1万5000人対象

第一生命HD、副業解禁 1万5000人対象―大手生保初

IHI、国内8000人の副業解禁 重厚長大企業も転機

IHI、社外兼業を解禁 社内副業もルール化
0436デフォルトの名無しさん
垢版 |
2022/01/02(日) 21:56:13.39ID:Uu3cvt4h
効率を求め過ぎてモノリシックになりすぎると様々なコストが上昇してしまう
そこで分割
さらに内部もcrate分割で並行コンパイル
0437デフォルトの名無しさん
垢版 |
2022/01/04(火) 02:27:09.98ID:L+p8nbVX
Rustでノードが追加されたり消されたりする双方向グラフ扱いたくなったらどうするんだろ
Arenaじゃ追加削除してるうちにゴミがメモリ圧迫していくし
0438デフォルトの名無しさん
垢版 |
2022/01/04(火) 09:43:25.00ID:aGnbM+4r
>>437
Cursor使う

Arenaの場合はfree list用意して削除済み要素を再利用すればよい
Arenaが埋まったらreallocするのではなく同じサイズの新たなArenaを獲得していくようにすれば
不要になったArenaから解放できるからmalloc使う場合と同等のメモリ使用量に抑えられるかと
これでも不足するなら copy GC 的に compaction するしかなさそう
0439デフォルトの名無しさん
垢版 |
2022/01/04(火) 18:15:54.62ID:L+p8nbVX
>>438
なるほど…… 結構ガッツリ実装しなきゃいけなそうね。ありがとう。最後はGCを実装することになりそうなので、それならいい感じのGCを残しておいてくれたら良かったのにって気になるな
0440デフォルトの名無しさん
垢版 |
2022/01/04(火) 18:22:33.23ID:L+p8nbVX
Cursorってなんでしょう?
0442デフォルトの名無しさん
垢版 |
2022/01/04(火) 20:59:48.62ID:/2oFrrnl
>>439
GCを必要とする用途は非常にレア
だから標準ライブラリには不要だが外部ライブラリに色々あるので大丈夫
0444デフォルトの名無しさん
垢版 |
2022/01/04(火) 22:53:03.36ID:NZNEJALT
特殊な案件でしかGCを使うことはないため
その場合は汎用GCライブラリ利用よりも
データ構造とアロケーションとGCを密に設計する方がベターかも
0445デフォルトの名無しさん
垢版 |
2022/01/05(水) 00:28:17.64ID:GzN74lxE
ちゃんとしたスマートポインタを自作する時点で結構大変だから用途特化した方が確かによさそう
0446デフォルトの名無しさん
垢版 |
2022/01/05(水) 01:03:11.75ID:o/mlVe5X
グラフみたいなデータ構造を実装するだけでも、GCが必要になったりするもんなん?
0447デフォルトの名無しさん
垢版 |
2022/01/05(水) 01:37:16.98ID:hbslRCuW
>>441
ありがとうございます!
0448デフォルトの名無しさん
垢版 |
2022/01/05(水) 01:46:20.36ID:yOKwmyBj
グラフ構造表現するだけならArenaや、少し安全にするならGenerationalArenaで事足りるかと
copy GC的なものが必要になるのは大量にノードを作成してほとんど削除、一部残存みたいな状況でfreeできないArenaが残ってしまうケース
0449デフォルトの名無しさん
垢版 |
2022/01/05(水) 04:00:13.07ID:6kre97ZR
ちゃんとしたGCはないのに、参照カウントだけは標準ライブラリに入っていて循環参照には気をつけましょうねーって運用でカバーなのはなんか中途半端なものを感じる
そもそも参照カウントなんてGCとしてはかなりイケてない部類なのになんで参照カウントなんだ気持ちもある
0452デフォルトの名無しさん
垢版 |
2022/01/05(水) 07:42:18.23ID:jCayWhDI
単なるスマートポインタをGCと言っちゃうあたり・・・
あれは単にRAIIでヒープを処理してるだけのことであって
わざわざGCと呼ぶような大したもんではない
0453デフォルトの名無しさん
垢版 |
2022/01/05(水) 07:48:16.03ID:yhx54h3v
9分で轟沈したのに2時間後に死体蹴りせんでも。

LLVMにレジスタとスタック使わないよう教える術がないし
rustは意地でもスタックに置きたがるしplacement系が削除されたから保守的になるよね。
実際、保守的gcってどれくらい回収できんの?
0454デフォルトの名無しさん
垢版 |
2022/01/05(水) 07:52:39.60ID:/PNLes9I
>>449
即時解放がやりやすい&実装が簡単だから、だろ。

そういう説明をしないで>>452とか言うやつはRust普及の足を引っ張っているだけだから、書き込みしないほうがいいと思う。
0455デフォルトの名無しさん
垢版 |
2022/01/05(水) 08:39:25.19ID:yhx54h3v
>>454
>>450の言う通りrustのreference counting gcは
メモリ管理のためではなく共有された参照を数えるためのもので
シングルスレッド用のRcがあるのはrustがaffine typeだから
共有された可変を認めないからで、ついでに>>452の言うことも半分あってるよ。
rustは自動参照カウントにRAII併用するけどgcのない言語しか経験がない人が
gcをスマートポインタと混同するのもよくある事。

あと、rustの参照カウンタは弱参照があるから循環参照が切れる代わりに
単純な参照カウンタのオーバーヘッドが少ない・開放されるタイミングが
予測可能というメリットはないからrustが参照カウンタを用意する
メリットは>>450が指摘したものしか無いよ。
0456デフォルトの名無しさん
垢版 |
2022/01/05(水) 09:30:04.08ID:HAtvMNOo
学問的には参照カウントはGCの一方式として分類されるのが普通だよ
まあなんの前置きもなくGCといったらトレーシングGCがイメージされるというのもその通りだが
RcがGCだと言っても間違ってるということはない

RustのstdにトレーシングGCがないのは、単に標準ライブラリを大きくしない方針に従ってるだけじゃない?
本格的なGCが必要なケースは限られるし、外部クレートで十分と思うが
0459デフォルトの名無しさん
垢版 |
2022/01/06(木) 01:29:23.74ID:Izanmpcc
気持ち悪さは長文から来る。reference counting gcとかわざわざ参照カウントを英文で書いてカッコつける所も
減点項目。個人の主観的には文中に>>を挟む特徴が読み手の事を一切考えないオナニーに見える
0461デフォルトの名無しさん
垢版 |
2022/01/06(木) 08:47:42.41ID:zkS6fEay
文中に >> 挟むのだめなのか
どのレスのこと指してるのか明確になって良いと思うが
0462デフォルトの名無しさん
垢版 |
2022/01/06(木) 09:03:44.55ID:8b5imbdG
>>レス番
↑これで引用先に飛べるリンクが張られるの知らなさそう
5chにPCからアクセスしたり
専用ブラウザからアクセスしたときそうなってるのよ
0465デフォルトの名無しさん
垢版 |
2022/01/06(木) 16:21:52.81ID:a887VGZI
ダメというわけじゃないが、同じ人が言ってるわけじゃないのに文中に一つにまとめて自分の考えだけを
長々と話している時点で意味わからん、リンクの話じゃない。気持ち悪さがどこからくるかという話。
感想といえばその通りで、個人的な主観と言ってるが多くの人はそう感じるのはこうではないか?という話
0470デフォルトの名無しさん
垢版 |
2022/01/06(木) 21:11:27.35ID:Q5dnJVm5
>>469がいつものキチガイの典型例
文句をつける意味不明な書き込みをしてその後に自演で同意のレスを付けてくる
スレを荒らすことが目的
0472デフォルトの名無しさん
垢版 |
2022/01/06(木) 23:39:45.17ID:ZA0J9QW6
このスレ常駐の荒らしは以下の特徴があるから無視すればよい
「気持ち悪」「ゲロ」「汚」などの言葉を好む
別案・別情報・別解釈などを具体的に出せず文句を付けるだけ
そのような無意味な書き込みになぜか賛同レス
0475デフォルトの名無しさん
垢版 |
2022/01/07(金) 00:34:18.20ID:cXPu1ueH
>>463
コンパイル時にチェックされるものと実行時にチェックされるものがあるよ
多くの場合は前者で済むけど、可変参照を複数箇所で共有したい場合は後者が必要になる
0479デフォルトの名無しさん
垢版 |
2022/01/07(金) 08:58:17.17ID:3q+e3WNv
>>475
コンパイル時のチェックって結局人手で書いたコードによるチェックなんでしょ?
ということは担保は単体テストってこと?
0481デフォルトの名無しさん
垢版 |
2022/01/07(金) 09:25:48.12ID:9KLybwvT
そもそもだかマシン語でみりゃ
メモリに型もなんもないよw
単なるバイトだらけ
コンパイルの段階で変なコードか
けないようにしてるだけ
でもこれだとぬるぽ!が回避できないので
仕方なく仕組み入れたのがRustでしょ
0482デフォルトの名無しさん
垢版 |
2022/01/07(金) 10:01:43.31ID:FjJ2oZu9
Rust書くときは常にIDEに直してもらいながら書いてるから>>476みたいなの全然解けないわw
0487デフォルトの名無しさん
垢版 |
2022/01/07(金) 12:00:56.69ID:24FxYl/s
>>486
初心者向けにわかりやすく解説しようという試みは評価するが
間違いが多すぎて萎える
ここで初心者の質問に回答してる初心者と同じ
0489デフォルトの名無しさん
垢版 |
2022/01/07(金) 18:09:24.83ID:KzGvgOV1
>>488
整数型や浮動小数点型といったスカラー型の変数は、変数間の代入において所有権は基本的に複製されます。これを「所有権の複製(コピー)」といいます。変数間の代入などにおいて所有権は複製されるので、値の所有者は常に1個でなければならないというルールは守られます。
0493デフォルトの名無しさん
垢版 |
2022/01/08(土) 00:19:22.76ID:tLJ6VgIA
整数型とかの単純のヤツはCopyだかCloneだかをderiveしててデフォのmove semantics機能してなかった気がするな
最近書いてねぇから忘れてんなこれ(´・ω・`)
0494デフォルトの名無しさん
垢版 |
2022/01/08(土) 06:57:19.85ID:5x1u92SJ
数値型が特別扱いされているわけではない
Copy traitを実装すればcopyされる
Copy traitを実装しなければmoveされる
0495デフォルトの名無しさん
垢版 |
2022/01/08(土) 23:30:01.75ID:lz8RPHEi
Copyで複製されるのは所有権じゃなくて値だよね
代入先の変数が複製された新しい値の所有権を持つことになるけど、所有権が複製されるんじゃあない
0496デフォルトの名無しさん
垢版 |
2022/01/09(日) 16:14:36.11ID:uxfV5OFq
copyだけでなくmoveされるのも対象は値
所有権ではない

値をmoveした結果
値に紐付く所有権がくっついてくる
0498デフォルトの名無しさん
垢版 |
2022/01/09(日) 18:01:55.54ID:yd7evZmg
個人的に間違った捉え方をするのは自由だが
それを初心者に広めるのはやめていただきたい
0501デフォルトの名無しさん
垢版 |
2022/01/09(日) 19:18:00.80ID:n32zl2Pe
所有権が複製できちゃったら「一個の値に一個の所有者」ってルールが守れないやん(´・ω・`)
0505デフォルトの名無しさん
垢版 |
2022/01/09(日) 20:20:09.14ID:Yd6TUYc2
というかCあたりの関数の引数も
コピーじゃなかった?
中身を渡した先でもいじらせる場合とかは
ポインター渡しとかなんかやってた記憶
0507デフォルトの名無しさん
垢版 |
2022/01/09(日) 21:41:43.59ID:QVmVQA75
Cでポインタ型の値を渡してるだけのことを
参照渡しと言っちゃう害悪がネットにチラホラ残ってて悲しい
ポインタ渡しとかいうすっとんきょうな用語も必要性を感じない
Javaで単に参照型変数の値を渡してるだけのことを
参照渡しと言っちゃうのも割りとあって悲しい
0510デフォルトの名無しさん
垢版 |
2022/01/09(日) 22:21:03.82ID:uOSYnK8a
Rustは非常にシンプルで
Copy traitが実装されていない型は値と所有権がmoveされる
Cooy traitが実装されている型は値がcopyされてその値に新たな所有権が生じる

もちろんそれを所有権と値が複製されたとみてもよい
ちなみにRcは所有権の複製ではなく所有権の共有
0511デフォルトの名無しさん
垢版 |
2022/01/09(日) 22:28:10.17ID:ec1b4GYb
「所有権とは、文字通り変数が値を所有できる権利のことです。」
ふむふむ

「スカラー型の変数は、変数間の代入において所有権は基本的に複製されます。これを「所有権の複製(コピー)」といいます。」
ふむふむ・・・

「変数間の代入などにおいて所有権は複製されるので、値の所有者は常に1個でなければならないというルールは守られます。」
・・・は?
元の値を所有できる権利を複製したんじゃなかったの?
0512デフォルトの名無しさん
垢版 |
2022/01/09(日) 22:37:27.87ID:uOSYnK8a
>>511
所有権と値は必ずセットで複製される
当たり前だが片方だけが複製されることはありえない
必ず1対1の関係になる
ちなみにRcの場合は所有権は複製されずに所有権の共有となる
0515デフォルトの名無しさん
垢版 |
2022/01/10(月) 00:03:57.12ID:x5u3TTyT
>>509
複製された(結果的に値は同じだけどメモリ上の位置は異なる)新たな値に対する新たな所有権を「所有権が複製される」って表現するのはおかしいべ?


>>510
そこよく勘違いされてるけど値自体はCopyトレイトと関係なく常に複製されてるよ(最適化で除かれるとかは別として)

https://doc.rust-lang.org/std/marker/trait.Copy.htmlに全部書いてあるけど
Copyな型は「プリミティブ型みたいに単純にメモリの内容を複製するだけでオッケー=copy」
非Copyな型は「ポインタとか含まれてたりして単純にメモリの内容を複製するだけだとNGな可能性があるから古い方は使えなくするよ=move」
ってだけ
0516デフォルトの名無しさん
垢版 |
2022/01/10(月) 11:29:11.88ID:0oVbzL+8
>>515
ルールを守れるか守れないかという話。
表現としておかしいかどうかは結論なんて出せないんじゃね?公式ドキュメントででも謳ってない限り。
0517デフォルトの名無しさん
垢版 |
2022/01/10(月) 20:14:15.89ID:tVKp4zEB
著者のバックグラウンド見る限りC/C++の経験があるオレならRustも分かっちゃうよ?みたいな連載だから表現が慣れてなくても気にしない
監修もRustの人っぽくなさそうだし…多分、関数型の語彙が無いんじゃないかね
0518デフォルトの名無しさん
垢版 |
2022/01/10(月) 20:29:16.07ID:DRRBVfd3
うんこ言語を好意的に連載してる記事をこき下ろす性格の悪いRusterが集まる駄スレ
0520デフォルトの名無しさん
垢版 |
2022/01/11(火) 11:05:54.30ID:U35zy9ok
>>518
だよなぁ。
誰か筆者に指摘した?

あと、「所有権の複製(コピー)」はRustだと実際は何て言ってるの?
0522デフォルトの名無しさん
垢版 |
2022/01/11(火) 12:27:41.85ID:zYBpR5AJ
所有権だけをすることなんてないだろうし、そんな言葉なくね
そもそも意味わからん

処理系を実装してる人にとっては考えることかもしれんが
0524デフォルトの名無しさん
垢版 |
2022/01/11(火) 21:25:05.09ID:On+Ztxm9
まあ無駄にややこしいだけの説明だわな。
これで間違ってない!とか意地張るような輩は俺だったら落とすわ。
0526デフォルトの名無しさん
垢版 |
2022/01/11(火) 22:00:42.75ID:7fHp9GHd
所有権の複製の意味が分からん
不用意に独自用語使うのを野放しにしちゃいけない
専門用語とその定義がなぜあるのかを考えて欲しい
0527デフォルトの名無しさん
垢版 |
2022/01/11(火) 22:43:07.52ID:2061HgWk
>>519
実際に生ポインタ(アドレス)を見る形で実験したところ
「関数に値渡し(≠参照渡し)する」時は
「Copy trait実装の有無」に関係なく
「必ず値は複製されている(=別アドレスになる)」という
よく考えれば当たり前の挙動となった

つまり話をまとめると
・Copy trait実装の有無と関係なく「値は必ず複製される」
・Copy trait実装がある時は「所有権も複製される」
・Copy trait実装がない時は「所有権は移動する」
これ以外に表現しようがないことがわかった
0528デフォルトの名無しさん
垢版 |
2022/01/11(火) 23:09:26.60ID:On+Ztxm9
メモリ上の動きと言語上のルールの違いもまともに理解してなさそうな連中だな。
0529デフォルトの名無しさん
垢版 |
2022/01/11(火) 23:49:06.82ID:t1MM9BO+
mutの時に書き換えると元の値と別の値に出来るのだから新たな所有権が生じているのは事実
あとは、所有権の複製、という表現の問題
間違ってはいないが理解しにくいならば別の良い表現で置き換えればよいが何がいいだろう?
0532デフォルトの名無しさん
垢版 |
2022/01/12(水) 10:38:50.42ID:uD0wFQGQ
値を複製したらメモリの領域が別なのに「所有権の複製」は何を複製すると思ってんだろ
0534デフォルトの名無しさん
垢版 |
2022/01/12(水) 21:24:46.00ID:zdKxvEH9
全く同じものを新しく生成するのと複製は外から見て区別しようがないんだから
0535デフォルトの名無しさん
垢版 |
2022/01/12(水) 22:30:30.00ID:y9ayzVSo
所有権はコンパイル時のはなし
メモリの動きは実行時のははし
0537デフォルトの名無しさん
垢版 |
2022/01/12(水) 23:51:37.77ID:DMKGOQqO
現実世界の所有権が複製可能な権利だったのなら
複製されると勘違いする人がいても不思議はないが・・・
0539デフォルトの名無しさん
垢版 |
2022/01/13(木) 10:12:58.78ID:8S0jzhzB
権利のような無形物は質量保存則には縛られない

Borrow Checkerが課すルールをわかりやすく説明するためのメタファーとして
現実世界の所有権という概念を借りてきてるのに
そのメタファーを分かりにくくするエクストリームなルールを勝手に追加して広めるのはやめよう
0541デフォルトの名無しさん
垢版 |
2022/01/13(木) 11:03:58.63ID:4F526BmN
というかRustの実装のところ見ればいいんじゃね?
仕組みのコードはあるだろうし
0544デフォルトの名無しさん
垢版 |
2022/01/13(木) 12:30:05.91ID:H8cLP4dt
Ownershipを所有権と訳したから
「所有権とは、文字通り変数が値を所有できる権利のことです」
という間違った解釈がされて
さらには「所有権の複製」なんていうトンデモ説が出現しちゃう
0546デフォルトの名無しさん
垢版 |
2022/01/13(木) 14:28:13.33ID:LRlvXHH5
結局はどこにも原典がないオレオレ用語でワロタ
技術は研鑽していかないといけないのに
ポエムと独自解釈と拡大解釈によって逆方向に突き進むボンクラ
0547デフォルトの名無しさん
垢版 |
2022/01/13(木) 15:21:48.48ID:4OU2rK55
まぁ、オープンソースですらねぇし専門家の目すら通ってない様なサイトだし
それっぽい事書いときゃいいんだよってのが大抵のweb界隈

itで何か知りたいなら手っ取り早い話公式ドキュメント当たれって事だろ(´・ω・`)
0548デフォルトの名無しさん
垢版 |
2022/01/13(木) 15:31:14.25ID:iHsQmzfW
それでわかりやすくなるんなら別にいいけど、余計わかりにくくしてるってさぁ。。
0551デフォルトの名無しさん
垢版 |
2022/01/13(木) 16:19:48.57ID:VN3LqOp5
this is known as a move.
英語のほうだと「ムーブとして知られています」か

実際コンパイラのソースみてもownershipはtransferとかtakeっていう表現でmoveだのcopyとは言ってないね
0552デフォルトの名無しさん
垢版 |
2022/01/13(木) 16:53:50.81ID:qAhzUFbZ
>>549
公式リファレンスくらいは英語で読もうよ
そんな変なサイト見てるからOwnershipの意味すら取れなくなるんだぞ
0553デフォルトの名無しさん
垢版 |
2022/01/13(木) 17:08:41.31ID:2BXAobev
>>552
それは変なサイトではなくRust公式ページの日本語訳。
元のRust公式ページでも同様。

Ownership and moves
https://doc.rust-lang.org/rust-by-example/scope/move.html

Because variables are in charge of freeing their own resources,
resources can only have one owner.
This also prevents resources from being freed more than once.
Note that not all variables own resources (e.g. references)

When doing assignments (let x = y) or passing function arguments by value (foo(x)),
the ownership of the resources is transferred.
In Rust-speak, this is known as a move.
0555デフォルトの名無しさん
垢版 |
2022/01/14(金) 00:21:00.58ID:hAOjwXhX
DeepL で翻訳してみた

なぜなら、変数は自身のリソースを解放する役割を担っているからです。
リソースは一人のオーナーしか持つことができません。
これはまた、リソースが複数回解放されるのを防ぐためでもあります。
すべての変数がリソースを所有するわけではないことに注意してください(例:参照)。

代入(let x = y)や関数の引数を値で渡す場合(foo(x))。
リソースの所有権は移転する。
Rustの用語では、これを「移動」と呼びます。
0556デフォルトの名無しさん
垢版 |
2022/01/14(金) 00:30:32.83ID:hAOjwXhX
「所有権の複製」とか、意味の分からない事を書いている、香具師がいるのか?
0558デフォルトの名無しさん
垢版 |
2022/01/14(金) 02:45:20.76ID:InXswW/0
>>557
元の値の所有権はそのまま、複製された新しい値の所有権が新しく発生する。
元の値の所有権について何も操作は行われておらず、表現すべきことも無い。
0559556
垢版 |
2022/01/14(金) 03:32:18.88ID:hAOjwXhX
所有権が複製されるという書き方よりも、むしろ、

primitive を含むコピー型変数は、コピーされると、
所有権は移動しないので、元の変数にもアクセスできる、みたいに使う

コピーされると新たに、別のオブジェクト(実体・メモリ領域)と所有権が作られるとか
0560デフォルトの名無しさん
垢版 |
2022/01/14(金) 08:35:26.86ID:8BRe3wDd
- 所有権ごと複製するという表現がわかりやすいかわかりにくいか⇒人それぞれ
- 所有権を複製するという表現が逆になにか問題を生ずるか⇒今のところ挙げられてない
0562デフォルトの名無しさん
垢版 |
2022/01/14(金) 09:28:53.08ID:n8eH8EkW
>>558
これだよな
0563デフォルトの名無しさん
垢版 |
2022/01/14(金) 09:48:26.29ID:20065uel
所有権の複製では意味が通らない事は明らかなので、
誰か >>489 の文をサクッと直してくれていいんだぞ
0564デフォルトの名無しさん
垢版 |
2022/01/14(金) 09:59:56.29ID:wd6QtXqe
流れ見てると「所有権の複製」は

おかしいから使うな派が半分
おかしいけどまあ好きにすれば派が半分
おかしくない派が約1名

みたいな感じ?
0568デフォルトの名無しさん
垢版 |
2022/01/14(金) 21:39:59.21ID:+ggCJzG3
所有権というか、ポインタなのか、実体なのかって考えれば所有権もすぐに理解できると思うが
0569デフォルトの名無しさん
垢版 |
2022/01/14(金) 22:02:26.42ID:hgiR/8Zn
>>568
それは所有権を理解してないのでは?
0570デフォルトの名無しさん
垢版 |
2022/01/14(金) 22:22:42.07ID:8BRe3wDd
>>:567
1つだったものが2つになることを複製と呼ぶのはべつにわかりにくいとは思わんがなぁ
0571デフォルトの名無しさん
垢版 |
2022/01/14(金) 22:37:39.46ID:WRwvxAen
現実のものに例えると適する例がないけど
近い分野だとOSでのプロセスのfork()に近いかな
どちらも初期状態は同じでその後は別の道を歩んで値(メモリ)が別の値を取れるようになる
これをプロセスの複製と呼ぶから複製という単語自体はわかりやすいと思う
0573デフォルトの名無しさん
垢版 |
2022/01/14(金) 22:49:30.67ID:IfPg31YF
ジエンさんも複製されてるねw
0574デフォルトの名無しさん
垢版 |
2022/01/14(金) 22:54:57.45ID:k9ZagSOx
>>570
所有権は複製はできないが分割は可能
共有名義の不動産持分みたいなやつ
Rustに当てはめるとRcにあたる
0575デフォルトの名無しさん
垢版 |
2022/01/14(金) 22:59:38.88ID:8BRe3wDd
>>572
>だから「所有権」に関しては全く別物だろうがよ

「全く別物」という理由は?2つになるのは変わるまい。
0576デフォルトの名無しさん
垢版 |
2022/01/14(金) 23:04:12.94ID:8BRe3wDd
>>574
人それぞれだと思うが俺は所有権の分割って方がわかりにくいと思うがな。
Rcと紛らわしいから「複製」は使うなというのは納得できるが。
0577デフォルトの名無しさん
垢版 |
2022/01/14(金) 23:08:16.48ID:wd6QtXqe
>>571
プロセスはtask_structとかがあってしかも実際に複製されてるからな

Rustの所有権はそういうふうに実際にstruct Ownership;みたいのが有るわけじゃない
上の方でも言ってるやつがいるけどborrowcheckerとかのルールや制約を所有権って概念で説明してるだけ

だからメモリ上でCopyな(=単純なmemcpyで矛盾が起きない)型が複製されりゃ新しい所有権が作られるし!Copyな(=単純なmemcpyだと矛盾が起きる可能性が有る)型なら所有権もtransferされるってだけ
そこに解釈云々だのの余地はなく複製もクソもない
0578デフォルトの名無しさん
垢版 |
2022/01/14(金) 23:11:40.41ID:Gij7VB+L
>>571
そこで言う複製は値の複製
forkしてもPIDは複製されないのと同じで所有権も複製されない
0579デフォルトの名無しさん
垢版 |
2022/01/14(金) 23:13:06.72ID:hAOjwXhX
複製という用語は、2つの実体が作られたよりも、
その2つの同値性が強調される

例えば、一卵性双生児は同一の遺伝子だから複製だけど、
二卵性双生児は複製じゃない。
単に、別々の2つの実体が発生しただけ

二卵性双生児間には同値性が無いから

ただ、文書を書いた外人は、copy を同値性という意味で使っていない

長文で説明するのが面倒くさいので、copyという短い単語で、
単に、2つの実体が作られたみたいに、気軽に使っているのだろう

だから、copyを翻訳すると複製になってしまう
0580デフォルトの名無しさん
垢版 |
2022/01/14(金) 23:23:12.29ID:b+sgeTEs
複製という訳の問題じゃないよね
「所有権のコピー」と言っても「copy ownership」と言っても何も変わらない
0581デフォルトの名無しさん
垢版 |
2022/01/14(金) 23:34:11.11ID:b8FVBfqE
PIDとか二卵性双生児とか、根拠や脈絡がない例え話が次々に出てくるのが笑える。
なんでそこまで必死なのかと。
0582デフォルトの名無しさん
垢版 |
2022/01/14(金) 23:56:50.14ID:ErNyx2qm
fork出してきたお前が言うなやw
0583デフォルトの名無しさん
垢版 |
2022/01/15(土) 00:13:28.41ID:5R4N3qYj
>>571は曲がりなりにも根拠らしきものを挙げているけど
>>578のPIDはまったくの根拠レスじゃん、
forkで複製されないものを探したらPIDが出てきたとかじゃね?
0584デフォルトの名無しさん
垢版 |
2022/01/15(土) 01:02:15.31ID:l/1QpEiq
>>570
値はそうかも知れんが所有権は新しくできたものだろ。
新しくできたものを複製ってのは変だろうが。
0587デフォルトの名無しさん
垢版 |
2022/01/15(土) 02:34:21.16ID:LQYSNqi+
>>583
そう感じちゃうのがRustの所有権を理解してない何よりの証拠なんだよなぁ
0588デフォルトの名無しさん
垢版 |
2022/01/15(土) 08:00:13.06ID:SUNY4hKu
>>587
根拠を挙げて主張しているかそうでないかの違い。国語の問題。
所有権を理解しているかどうかは関係ないんだがお前さんの読解力にも問題があるな。
0589デフォルトの名無しさん
垢版 |
2022/01/15(土) 08:48:58.88ID:MrK/oPRe
根拠があるってんなら単にrust公式から定義をひっぱってくればいいのではw
それが無いから単なる珍妙なオレオレ用語で終了なんだよこの話は
こーいう手合いをいちいち構ってると時間足りないぞ人生は短いぞ
0590デフォルトの名無しさん
垢版 |
2022/01/15(土) 09:24:09.35ID:i5tbAI8Y
>>588
複製おじさん必死だなww
0591デフォルトの名無しさん
垢版 |
2022/01/15(土) 10:37:04.68ID:SKIF+upB
もう誰か本家のissueに「CopyとMoveって何をcopy、moveしてるの?所有権のcopyっておかしい?」って突撃してこいよw
0592デフォルトの名無しさん
垢版 |
2022/01/15(土) 10:38:54.35ID:zYbpVr1V
スレ追い切れてないけど所有権だけcopy/moveしてるという主張してる人がいるの?
0595デフォルトの名無しさん
垢版 |
2022/01/15(土) 12:21:18.07ID:NVDl8gUD
参照の説明に合わせてCopy Typeには所有権は無いという捉え方ならかろうじて理解はできる
0596デフォルトの名無しさん
垢版 |
2022/01/15(土) 13:06:56.98ID:SKIF+upB
>>593
おれら匿名の有象無象におかしいって指摘されても聞く耳持たねぇみたいだから本家でぶった切られてこいっていう皮肉なw
0597デフォルトの名無しさん
垢版 |
2022/01/15(土) 16:47:14.84ID:MrK/oPRe
Cでポインタへのポインタをダブルポインタと言い張ったり
Cで関数へポインタで値渡ししてるだけのことを参照渡しと言い張ったり
酷いと思わんかね?
思わん人も居ることのほうが問題
0598デフォルトの名無しさん
垢版 |
2022/01/15(土) 17:52:02.36ID:gzKdcX6j
>Cでポインタへのポインタをダブルポインタと言い張ったり
>Cで関数へポインタで値渡ししてるだけのことを参照渡しと言い張ったり
c++でポインタ渡しを参照渡し言うならそりゃ誤解は出てくるが、そんなに問題にならんわ。
てか extern C で参照渡しは普通にポインタ扱いになるしな。
rustで所有権のコピー言うのは明確に意味がおかしい。
0599デフォルトの名無しさん
垢版 |
2022/01/15(土) 18:25:43.70ID:V6fKEShR
もうええやろこの話題は…こんな枝葉の問題でギャーギャー騒いでたら何も身につかんで…
Rust棒を使って気に食わないやつを殴りたいだけなんか…?
0601デフォルトの名無しさん
垢版 |
2022/01/15(土) 19:00:19.86ID:Pt/mdzot
c++23以降で契約プログラミングのサポートが入るらしいけど、rustって言語レベルで契約プログラミングサポートしてる?
0602デフォルトの名無しさん
垢版 |
2022/01/15(土) 19:35:04.98ID:Ipn+w0vn
1週間以上も議論が続いている原因はおそらく
copyとmoveの対象の非対称性にあると思う

Copy trait非実装の型は「所有権がmoveされる」
Copy trait実装の型は「値がcopyされる」そして「新たな所有権が生じる」
0607デフォルトの名無しさん
垢版 |
2022/01/15(土) 21:44:00.10ID:+D8ShBal
俺は中立派なので
「Copyトレイト実装型は値と所有権が複製される」
でも構わないし9割以上の人々にはこれで通じるだろう
あとはどこまでこだわるかだけだ
これ以上その表現は容認できないと続けるならばスレ荒らしと変わらない
0608デフォルトの名無しさん
垢版 |
2022/01/15(土) 21:52:50.82ID:MrK/oPRe
>>607
「所有権の複製」は根拠の無いオレオレ用語であり
rust公式による定義は一切示されなかった

でオシマイの話
議論ですらないし
どっち派という派閥の話でもない
0609デフォルトの名無しさん
垢版 |
2022/01/15(土) 22:04:56.72ID:Ipn+w0vn
一般的に「批判や反対だけならバカでもできる」と言われるので
ここは代替案、修正案、改善案を示してはどうだろうか?
0610デフォルトの名無しさん
垢版 |
2022/01/15(土) 22:09:17.84ID:im+Hgbd+
匿名掲示板のやりとりで意見を変える人なんていないしとっとと次の話題に移るに限る
0611デフォルトの名無しさん
垢版 |
2022/01/15(土) 22:17:16.04ID:xn0tLhqJ
複製おじさんが必死過ぎて草www
自分の間違いに気づいてもなお苦し紛れの言い訳テラワロスw
0612デフォルトの名無しさん
垢版 |
2022/01/15(土) 22:29:40.11ID:SUNY4hKu
>>597
参照渡しという用語は定義があるからCのポインタ値渡しに使うのは明らかに間違いなわけだが
ダブルポインタの方は正式に仕様で規定されているわけではないが俗語として通用しているな。
俗語だから前提無しに誰にでも通じるわけじゃないというところ注意が必要だが。
0613デフォルトの名無しさん
垢版 |
2022/01/15(土) 22:30:43.34ID:daomKUdj
複製おじさんは自演して複数人を装ういつもの人

いつも間違いを指摘されるが全く反省せず
嘘を書き続けて強弁しつつ自演擁護するのが趣味
C++じいさんと一緒にここに隔離されてる
0614デフォルトの名無しさん
垢版 |
2022/01/15(土) 22:33:34.89ID:im+Hgbd+
所有権も複製されるとするとrustの所有権システム破綻するの?
そういう話ではなくて用語の用法に違和感があるという議論だよね?
理解合ってる?
0615デフォルトの名無しさん
垢版 |
2022/01/15(土) 22:44:35.60ID:Ipn+w0vn
>>614
その通り
俺は既に書いたように
『Copy trait実装の型は「値がcopyされる」そして「新たな所有権が生じる」』だが
これを『値と所有権が複製される』と表現する人がいても特に困らないしRustの理解で破綻することもない
現実にある所有権に照らし合わせると『所有権の複製』という用法に違和感があるだろうという話
0616デフォルトの名無しさん
垢版 |
2022/01/15(土) 23:04:44.12ID:psZvEbv8
>>613
今日いきなり「複製おじさん」とかいう特異な単語を使う人が立て続けに現れたんですがw
0617デフォルトの名無しさん
垢版 |
2022/01/15(土) 23:42:27.61ID:IhXEZL2k
>>614
複製されたら破綻するよ
当たり前じゃん
所有権を何だと思ってんの?
わかってないの複製おじさんだけだよ
0618デフォルトの名無しさん
垢版 |
2022/01/16(日) 10:16:15.91ID:FbMoDLfJ
>>614
>所有権も複製されるとすると

所有権は複製されない。
0619デフォルトの名無しさん
垢版 |
2022/01/16(日) 10:41:29.77ID:78YeqR3t
一週間バカにされ続けても自ら学ぼうとしないメンタルすごいよな

記事書いたやつも複製おじさんも所有権を変数単位のフラグみたいに認識してるんだよ
Copyなら変数の値をコピーして所有権フラグの値もコピーするイメージ(何か問題でも?w)

現実の所有権のように各所有権が個別リソースに紐づくと考えてないから「所有権を複製」しても問題ないと思っちゃう

所有権のメタファー台無し
0620デフォルトの名無しさん
垢版 |
2022/01/16(日) 10:49:19.61ID:78YeqR3t
>>617
>所有権を何だと思ってんの?
この質問に答えられるようなら1週間前に終わってる話
自信がなくバカにされるのが怖くて答えられない
だから自演して印象操作に走ってしまう
それで余計にバカにされちゃう悪循環
0621デフォルトの名無しさん
垢版 |
2022/01/16(日) 10:53:40.34ID:zLzfdhk5
Rustスレは

仲介イテレータおじさん
所有権の複製おじさん
算数100点おじさん

の提供でお送りします
0624デフォルトの名無しさん
垢版 |
2022/01/16(日) 14:09:05.15ID:KLhMVNjz
しょーゆー拳!の複製とは・・・所有してない事では・・・?それとも共有?創造イテレーターおじさん。。。
0625デフォルトの名無しさん
垢版 |
2022/01/17(月) 22:59:06.94ID:Y2e2eRad
Rust 1.58で使えるようになったね

let var = 123.45;
assert_eq!(" 123.450", format!("{var: >10.3}"));

let vec = (5..=9).collect::<Vec<i32>>();
assert_eq!("[5, 6, 7, 8, 9]", format!("{vec:?}"));
0626デフォルトの名無しさん
垢版 |
2022/01/19(水) 19:54:17.44ID:E5BGSNnr
rust学習してるんだけど
コンパイル時検査で並列処理の安全性(可変参照が1つである事)を証明できるんだろうか?
実行時に借用チェックが行われてるという説明があったけどそれは必要なの?
0627デフォルトの名無しさん
垢版 |
2022/01/19(水) 19:59:57.13ID:E5BGSNnr
勘違いかも
この記事実行時にチェックしてるという意味じゃないかもしれない
0628デフォルトの名無しさん
垢版 |
2022/01/19(水) 21:18:54.23ID:gQYkvdGO
>>626
複数スレッドから参照される変数はコンパイル時に保証できないから実行時に保証されるよ
Mutexとか
0629デフォルトの名無しさん
垢版 |
2022/01/19(水) 21:23:52.62ID:tIKoVln/
Rc<RefCell<T>>のように所有権が共有されてる値を変更する場合なんかは実行時チェックしかできない

interior mutability patternと呼ばれるやつはみんなそう
0631デフォルトの名無しさん
垢版 |
2022/01/20(木) 10:26:42.45ID:O3OMKZ6x
実行時に動的に借用のチェックをさせたいという動機は分かるんだが
RefCellっていう名前でそれが表現できてると思えないし
一方で内部可変性を表現してるとも思えないし
そもそも内部可変性と実行時借用規則強制と二つのことが一つの名前になってるし
じゃあどうすべきだったということも思いつかないけど
なんかモヤモヤしてる
0632デフォルトの名無しさん
垢版 |
2022/01/20(木) 12:30:05.06ID:Rdmkjysn
Cell<T> は Mutable<T>
RefCell<T> は DynamicMutable<T>

Cellが何かを一度イメージできるようになると
今のネーミングでも困らないから名前が変わることはないと思う
interior mutabilityという名前も最初は分かりにくかった
こっちはまだ変わる可能性あると思う
0634デフォルトの名無しさん
垢版 |
2022/01/20(木) 12:41:15.85ID:lj0NmUaq
あー、なるほど、名前が分かりづらいのはおれが日本人のせいなのかな、とか思ってたけど、やっぱり慣れてないと分かりづらいネーミングだったか
0636デフォルトの名無しさん
垢版 |
2022/01/20(木) 13:18:31.58ID:hnvUf8sg
>>631
中身を書き換えられる『セル』という分かりやすい名前
Cellは内部可変がOK
RefCellは内部可変参照がOK

違いが分かりやすいように3種類を持つ構造体を用意
struct S {
a: [i32; 3],
c: Cell<[i32; 3]>,
r: RefCell<[i32; 3]>,
}
let s = S {
a: [1, 2, 3],
c: Cell::new([1, 2, 3]),
r: RefCell::new([1, 2, 3]),
};
// s.a = [4, 5, 6]; // コンパイルエラー (sがmutじゃないため)
// s.a[1] = 5; // コンパイルエラー (sがmutじゃないため)
s.c.set([4, 5, 6]); // OK 内部可変
{
let mut p = s.r.borrow_mut(); // OK 内部可変参照
p[1] = 5;
// このブロックを抜けるとborrow自動返却
}
assert_eq!([1, 2, 3], s.a);
assert_eq!([4, 5, 6], s.c.get());
assert_eq!([1, 5, 3], *s.r.borrow());
0637デフォルトの名無しさん
垢版 |
2022/01/20(木) 13:20:34.04ID:O3OMKZ6x
メソッド名が動的←→静的と対称的であったりもしないし・・・

Cell: get, get_mut, set
RefCell: get_mut, borrow, borrow_mut

ただしget_mutはそれぞれ
https://doc.rust-lang.org/std/cell/struct.Cell.html#method.get_mut
> this method expects self to be mutable, which is generally not the case when using a Cell.
https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.get_mut
> this method expects self to be mutable, which is generally not the case when using a RefCell.
とあり通常の用途とやらで考えると

Cell: get, set
RefCell: borrow, borrow_mut

共に"Cell"で内部可変性を表現しつつ
用途はメソッド名で十分わかるしまぁもういいのかこれで
0638デフォルトの名無しさん
垢版 |
2022/01/20(木) 13:27:05.24ID:O3OMKZ6x
>>632
>>636
Cellっていう短い名前にクッキリした役割を描いたのはRust陣営は成功かもね
Rust以前に前例があるかどうかは知らんけど

>>634
名前の説得力が不足してる疑いはあるよね

>>635
それなw
0639デフォルトの名無しさん
垢版 |
2022/01/20(木) 13:39:18.98ID:hnvUf8sg
>>637
Cell⇔RefCell は 静的⇔動的 の関係ではない
Cell⇔RefCell は 直接⇔参照 の関係
そのため余分にRefが付く

静的⇔動的 の関係にあるのは
「&」⇔「RefCell::borrow()」)
「&mut」⇔「RefCell::borrow_mut()」
0640デフォルトの名無しさん
垢版 |
2022/01/20(木) 13:52:05.11ID:O3OMKZ6x
>>639
少なくとも構造体の説明としては

https://doc.rust-lang.org/std/cell/struct.Cell.html
> A mutable memory location.

https://doc.rust-lang.org/std/cell/struct.RefCell.html
> A mutable memory location with dynamically checked borrow rules

↑のように書いてあるね
だから
SCell // A mutable memory location with statically checked borrow rules
DCell // A mutable memory location with dynamically checked borrow rules
こんなんでもよかったんじゃないかなぁと思ったがこれはこれで石投げられそう
0641デフォルトの名無しさん
垢版 |
2022/01/20(木) 14:13:35.66ID:hnvUf8sg
>>640
それは違う
間違った解釈で無関係な場所に「with statically checked borrow rules」を付けてはいけない

参照借用規則『multi readers xor single writer』に対して
以下が「静的チェック⇔動的チェック」の関係にある
静的チェック: multi「 &」xor single「&mut」
動的チェック: multi「RefCell::borrow()」xor single「RefCell::borrow_mut()」

一方でCellとRefCellの関係は
内部可変性が「直接書き換えOK」⇔「参照書き換えOK」の関係
だからCellに対してRef(参照)が付くRefCellという名前になっている
そして参照となるRefCellに対してのみ上述の参照借用規則が適用される
0642デフォルトの名無しさん
垢版 |
2022/01/20(木) 14:23:25.93ID:O3OMKZ6x
>>641
なるほどね

https://doc.rust-lang.org/std/cell/struct.Cell.html#method.get_mut
> If you require interior mutability by reference,
> consider using RefCell which provides run-time checked mutable borrows through its borrow_mut method.

↑ここでもまずは「参照による内部可変性が必要な場合は」と先に来てるね
「実行時に動的に借用のチェックをさせたいという」のが動機だと俺勝手に思いこんでたけど
それは一番じゃないみたい
0643デフォルトの名無しさん
垢版 |
2022/01/20(木) 14:32:46.88ID:XZNQ8H/m
>>635
Cell/RefCellと違ってBoxは分かりやすくていい名前だと思うぞ
Boxing/Unboxingは他の言語でも普通に使われてるよね?
旧名のOwned<T>や代替案のHeap<T>に比べると確実にいい
0644デフォルトの名無しさん
垢版 |
2022/01/20(木) 14:45:20.72ID:nm3lJD8v
Boxing/UnboxingはC#やJavaにもあるからBoxには全く違和感なかったけど
よく考えるとソースコード上にBoxという文字列が出現するのはRustだけかも?
0645デフォルトの名無しさん
垢版 |
2022/01/20(木) 14:54:02.35ID:3oKX7/s6
Scheme でも次の規格に Box が入ることになっている。
(既に導入している処理系も結構ある。)
0646デフォルトの名無しさん
垢版 |
2022/01/20(木) 15:32:21.48ID:hnvUf8sg
通常の型TやBox<T>などがSend+Syncである一方
Cell<T>とRefCell<T>は!Send+!Syncであることと引き換えに内部可変性を得ている
つまりmutではない参照の内部にあったとしても
「Cell<T>」は「mut T」のように成れて直接書き換え可能
「RefCell<T>」は「&mut T」を得られて参照書き換え可能
ここでCellとRefCellの違いは「&」すなわち「Ref」だからこの命名自体は分かりやすいと思う
0647デフォルトの名無しさん
垢版 |
2022/01/20(木) 16:52:16.46ID:O3OMKZ6x
>>644
むしろJava等にあるからこそ戸惑ったわ
既にあるBoxing/Unboxingへの理解に対して
Rustでは突如構造体としてBoxだもん
0648デフォルトの名無しさん
垢版 |
2022/01/20(木) 23:14:12.74ID:c3YxPrqk
まあBox と名前を合わせてBoxCellとか逆にBoxをRefにするかした方が統一的な名前づけだったとは思う。
0649デフォルトの名無しさん
垢版 |
2022/01/21(金) 07:08:34.56ID:zwVIa7Oi
>>648
Box<T>はヒープ上にTの場所を確保してそこを指し示します
Cell<T>はヒープ上かどうかは無関係で例えば>>636の使用例では全てスタック上
したがって「Boxと名前を合わせてBoxCellとか」はおかしいです

TとCell<T>はメモリ上の格納場所も実体も同じです
つまりCellとは内部可変性という特性を与え示していると考えたほうがわかりやすいでしょう
RefCell<T>も同様ですがこちらは参照借用規則の実行時チェックのためのborrowフラグが余分に確保されます

もうひとつの「BoxをRefにするかした方が統一的な名前づけだったとは思う」もおかしいです
refは参照(reference)の略としてあちこちで使われておりヒープ上かどうかは無関係ですが
Box<T>はあくまでもTがヒープ上にあることが主眼です

余談ですがこの関係でRefといえばstd::cell::Refという構造体があり
これはRefCell::borrow()が返す型として直接意識することはなく使われています
ちなみにRefCell::borrow_mut()が返す型はstd::cell::RefMutです
0650デフォルトの名無しさん
垢版 |
2022/01/21(金) 10:40:22.86ID:a7B69/kD
何も分かってねーなこいつ。
なぜBoxにするか、なぜRefCellにするかってのは要するに構造体のサイズを決定できない場合を想定してるわけよ。
スタックにそういういう動的にサイズが異なる実体をおくことも最近のコンパイラではないこともないが、通常はヒープに置くわ。
文字通りしか考えないで実際の使い方なんか一切考えないやつってのが丸わかりになるって意味では
分かってなさそうなやつにこの辺りについて問いただすってのは割と良いかも。
0651デフォルトの名無しさん
垢版 |
2022/01/21(金) 11:50:08.61ID:ePel1TKs
皆の言ってることがよくわからん
そもそもBoxとRefCellって対比させるようなものか?
0653デフォルトの名無しさん
垢版 |
2022/01/21(金) 13:03:50.49ID:ePel1TKs
RefCell<T>はTへのrefが作れるCell (実行時にborrow checkする)
TとBox<T>はborrowに関しては同じ振る舞いでデータの場所がヒープか否かの違い
全然関係性違うと思うんだけど
0657デフォルトの名無しさん
垢版 |
2022/01/22(土) 00:49:37.07ID:FWRR5JB/
ダメです
明らかにおかしい
ポインタ渡しと参照渡しを間違えてるくらいにはおかしい
0658デフォルトの名無しさん
垢版 |
2022/01/22(土) 01:05:08.77ID:7E1QrPk4
それは解釈のレイヤの問題。
JIS の情報処理用語の定義では参照呼び (参照渡しという言葉は定義がないが実質的に同じだろう) はオブジェクトの場所を渡すことと定義されていて、
ポインタという形で場所を渡すのも参照呼びの一種ということになる。
言語仕様の話をしているところで異なるレイヤが混ざるのはおかしくはあるが、
実例を示そうとしたり、逆に抽象的に説明しようとしたりすると境界が曖昧になることはある。
0660デフォルトの名無しさん
垢版 |
2022/01/22(土) 19:59:43.90ID:n0owABsu
>>658
ポインタ渡しと参照渡しが同じなら、nullptrを渡すのと同じことを参照渡しでどうやるか教えてくれ。
0662デフォルトの名無しさん
垢版 |
2022/01/22(土) 20:32:06.98ID:9yXjOkuN
ポインタ渡しっていう用語も使わないでほしい
ポインタ型の時に特別なもんでもなんでもなく
他の場合と同じcall by valueなのだから
0666デフォルトの名無しさん
垢版 |
2022/01/22(土) 23:09:33.04ID:j/zdYx9z
>>654
>BoxとRefCellには共通点も類似性も関係性も何もない
そうそう、何の共通点も類似性も関係性もないのに
The BookではBoxとRefCellを対比させてどういうケースにどっちを使うかわざわざ解説してるんだよなぁ
何の共通点も類似性も関係性も無いにも関わらずw
0667デフォルトの名無しさん
垢版 |
2022/01/22(土) 23:45:04.56ID:YZScTEQ/
>>666
マジでその二つは関連も類似も何もない
大きく分類してもBoxはスマートポインタの一種だが
RefCellはスマートポインタではなく内部可変性という性質の指定のみ
0669デフォルトの名無しさん
垢版 |
2022/01/23(日) 01:50:05.66ID:N2HN4NXS
clippy様がvoldemort typeを説明せよと仰せなのだが
もしかして、名前を言ってはいけないあの人のことをご存じない?

>>668
そこはinterior mutabilityの前提としてborrowing rulesを
おさらいするためにBoxを出してるだけだから違うだろ。
多義的なオレオレ用語が多くて質は悪いけど
the bookに意味もなくBoxとRefCellを登場させてる章なんてなかったと思う。
0673デフォルトの名無しさん
垢版 |
2022/01/23(日) 15:19:04.05ID:Qjn377p7
rust勉強しはじめたばかり、C,C++はだいぶ昔少し経験がある程度

Cとかじゃ、constなpointerは、変数自体がconstと、指ししめす対象自体がconstである場合があり
const T * const p;
みたいな宣言があったが

Rustはデフォルトでイミュータブルなのはわかるけど、mutを付けると、変数自体も指し示す対象もmutableになってしまう?

let mut v = vec![1, 2, 3];
v.push(2);
v = vec![4,5,6];

どっちか一方を禁止する方法とかあるのですか?
0674デフォルトの名無しさん
垢版 |
2022/01/23(日) 17:38:28.44ID:v0FQj8Ao
C上がりのヤツって意味のないところにconst付けがち
関数の引数にconst DWORD vとか
0675デフォルトの名無しさん
垢版 |
2022/01/23(日) 19:54:52.69ID:GGOFm3A0
>>673
どういうことをしたいのかによるけど
let x = Vec![...];
let mut y = &x;
みたいにすればyは再代入可能だけどxやvecの中身は変更不可になる
0679デフォルトの名無しさん
垢版 |
2022/01/23(日) 23:46:00.51ID:QpDxG2zZ
ちなみにRustでのconstとはコンパイル時点で定数(どんな複雑な型でもよい)であること
プログラミング言語によってはconstなのに実行時に決まる値(がその後変化しないこと、つまり単なるimmutable)を意味しているので意味の差に注意
0680デフォルトの名無しさん
垢版 |
2022/01/23(日) 23:59:31.12ID:2V1gRdrY
>>674
Rustでは関数の引数にconstはないな
ジェネリクスとしてのパラメータにはconstがありこちらは便利
0681デフォルトの名無しさん
垢版 |
2022/01/24(月) 00:27:06.65ID:bSZB9aci
>>675
ありがとうございます。
やりたいことは、だいたい同じですけど、少し違って
v.push(2)か再代入のv= vec![4,5,6];のどちらかを禁じたいでしたけど
あなたの投稿みて考えて

let v = &mut vec![1, 2, 3];
v.push(2);
//v = vec![4, 5, 6]; エラーになる

で一応できました。
でも再代入可能で、中身変更不可にvをする方法は思い浮かびませんでした。
675のようにして、vからyに代入したらyはそうなりますが。
0682デフォルトの名無しさん
垢版 |
2022/01/26(水) 20:11:49.47ID:IHm+4QQV
すまんが、Replit使って学習してるんだけどさ
たまたま海外勢の動画見たら、同じReplitのはずなのに波線の指摘とかコード補完とか効いててびっくりしたわ
https://www.youtube.com/watch?v=MsocPEZBd-M
うちではこんなのならないんだけど・・・・やり方わかる人いたら教えてくれんかな?
0683デフォルトの名無しさん
垢版 |
2022/01/26(水) 22:40:12.84ID:e2k0MxNT
Repl.itは、リンターやデバッガーからサードパーティのパッケージ、ホスティング、デプロイまで、

すべてを備えた、ブラウザー内の完全な共同クラウド開発環境です
0688デフォルトの名無しさん
垢版 |
2022/01/30(日) 19:13:28.33ID:9ei8l7Ku
コンパイル時に判明しないゼロ除算やオーバーフロー除算 ex. -128_i8 / -1_i8 はpanicとなるので
それが困る場合はchecked_div()を使えばOption型が返りNoneとなる
0690デフォルトの名無しさん
垢版 |
2022/01/30(日) 21:12:48.50ID:2J0C/Vn/
const fn divide(x:i32, y:i32) ->i32 {
x / y
}

let x = divide(1, 0); //panic
const y: i32 = divide(1, 0); //compile error
0691デフォルトの名無しさん
垢版 |
2022/01/31(月) 00:45:03.08ID:wgfsi16C
>>690
定数式の文脈でゼロ除算起きるとコンパイルエラーになるのはある意味当然だと思うんだけど
そうじゃないところでエラーになるのが意外だった
デバッグビルドでもMIRの最適化とかで定数畳み込みみたいなことやってるのかな
0692デフォルトの名無しさん
垢版 |
2022/01/31(月) 07:35:21.99ID:qlFEomu1
>>691
Rustではconst fnな関数を使ってconstな定数を作ることができる
つまりコンパイラがその定数を算出するためコンパイル時点で判明する
0693デフォルトの名無しさん
垢版 |
2022/01/31(月) 10:25:13.89ID:y6tOo2ii
とあるデータフォーマットを扱うライブラリを作っています。
一定形式のレコードが連続で書き込まれて最後には終端レコードが書き込まれるという単純な形式です。
Rust 上でもレコードを追加するのと終端処理のふたつのメソッドがあるだけです。
要は ↓ のように使えるライブラリだということです。

let mut file = File::create("file.hoge").unwrap();
Hoge::new(&mut file).add_entry("string1")?.add_entry("string2")?.finish();

このとき
・ 終端処理は必ずしたい
・ 終端処理はエラーの可能性もあり、それは捕捉したい (ので drop でさせられない)
という制約を静的に表現できるでしょうか?

現状では終端処理のメソッドが実行されたときにフラグを立てておいて
drop 内でそのフラグを検査するという形にしています。
可能ならコンパイル時に発見できるようにしたいです。
0694デフォルトの名無しさん
垢版 |
2022/01/31(月) 11:02:40.38ID:qlFEomu1
エラーを捕捉したいことをデストラクタに任せない
つまりそのような終端処理はdropされる前に終える
例えばBufWriter利用時も終える時は明示的にflushを呼ぶ
そしてflushはResultを返しエラーが判明する
0695デフォルトの名無しさん
垢版 |
2022/01/31(月) 11:32:28.54ID:LhFaS6j7
finishの呼び忘れを静的に捕捉したいということだからflushの例では不十分かな
add_entryの戻り値型の暗黙のdropを防げばいいけど、そういった機能はまだない(RFCにはあるけど進んではない)

https://users.rust-lang.org/t/prevent-drop-at-compile-time/20508
このスレッドではdropの実装に存在しないC FFI呼び出しを書いておいて、リンクエラーとして捕捉する方法が提案されているね
0696デフォルトの名無しさん
垢版 |
2022/01/31(月) 11:35:46.57ID:y6tOo2ii
>>694
それを制約として表現できるか (終端処理をしていないときにエラーになるように制約を書けるか) という質問をしてる。
つまり出来ないってこと?
0697デフォルトの名無しさん
垢版 |
2022/01/31(月) 11:53:47.47ID:y6tOo2ii
>>695
それは残念。

言語の機能として用意されてないまわりくどい方法を使うと
エラーメッセージがよくわからん (本来の問題とは違う内容が出てくる) ことになりがちだし、
使うときに unsafe や forget をいちいち書いてもらわなきゃならないのは
ライブラリとして提供するときにはちょっと汚すぎるなぁ。
0700デフォルトの名無しさん
垢版 |
2022/01/31(月) 12:47:03.61ID:qlFEomu1
>>696
なるほど
コンパイラは解析してdropさせるべき位置を把握しているから
そこへ至る全ての経路上で例えばFinalize trait実装型はそのメソッドfinalize()を呼んでいないとコンパイルエラーとなる
というような制約をするFinalize trait
が存在していれば要望を満たす?
0702デフォルトの名無しさん
垢版 |
2022/02/01(火) 18:21:42.44ID:EUosKgIx
amazon primeの記事経由でegui見てみたが結構いいな
ネイティブで試してみたが充分実用レベル
0703デフォルトの名無しさん
垢版 |
2022/02/01(火) 21:04:57.74ID:YxH4csZd
GCは標準からは消えたけどライブラリでやればいいってかつてこのスレで言われたことがあるのだが、GCライブラリのデファクトスタンダードってどれだ
0705デフォルトの名無しさん
垢版 |
2022/02/01(火) 22:04:01.37ID:YxH4csZd
>>704
いや一部だけGC欲しい時は普通にあるからそれは言い過ぎ
0708デフォルトの名無しさん
垢版 |
2022/02/01(火) 23:23:08.93ID:rLXhSAw+
>>702
eguiは毎回60fpsで全画面を描き直すことで差分描き直しを避けて簡単にしてるようだけど
省力化したい方針と合わないや
ゲーム向き?

>>705
GC使ってもRustのRAIIを無くせるわけじゃないから
そういう時はVecに入れて使って
あとは任意のタイミングで未使用の要素の区画を再利用という感じにしてる

>>706
Rustは各種bookを読んであとはstd docとreference見ながら
コンパイルエラーの通り直すだけで何とかなるから書かれている通りだね
付け加えると基本要素については覚えていないメソッドのために回り道しがちなので
Option Result slice str Iteratorあたりの全メソッドは一通り認識しておくといいかな
0711デフォルトの名無しさん
垢版 |
2022/02/02(水) 18:24:25.46ID:LUGaOk8s
>>706
>Mistake 3 : Start by implementing a graph based algorithm
その通りだとは思うけどRustと相性の良いアルゴリズム集的なのは欲しいとも思う
0712デフォルトの名無しさん
垢版 |
2022/02/02(水) 19:18:50.51ID:aYiI+nmg
>>711
汎用データ構造の大部分を使うな、という話になりそうだからなぁ。
スタックとキューくらいは楽に使えるのかね。
0713デフォルトの名無しさん
垢版 |
2022/02/02(水) 20:06:31.96ID:9W9+AwqU
dynや lifetime heavyは失敗しながら学ぶのでいいと思う
普通の人はしばらくやってれば気づくから
0715デフォルトの名無しさん
垢版 |
2022/02/02(水) 22:05:12.51ID:cdYzXGt/
データ構造が大事なんだって言われながら育ってきた身としちゃあ辛い話じゃねえか

自分で作らなけりゃいいんだな!ってslab_tree使って
「ある条件に合致した子ノードから、ルートまでの値をリストで取り出す」
みたいな処理を書こうとしたら怒られるんだよな。
node_ref.parent() : &Self<T> -> Option<NodeRef<T>
っていう型なもんだから、次々に親をたどるために
while Some(parent) = node.parent() { node = parent; ...}
みたいな処理書くと、当然怒られる。

何とか抜け道無いかって探したら、node自身じゃなくてそのIDを使えばよかったんだけど、
いつも抜け道があるとは思えない。辛い。
0716デフォルトの名無しさん
垢版 |
2022/02/02(水) 22:39:17.87ID:O+j3A95O
Rustで普通にやってるとスレッドセーフを強いられるから制約がキツくなるんだよね
0717デフォルトの名無しさん
垢版 |
2022/02/02(水) 22:41:53.47ID:J71gX0gE
大昔からの単純なポインタ相互参照だと
ダングリングポインタ・多重解放・解放忘れなどが全く存在しないことを検証すべき範囲が一般的には広くなりすぎる
もし狭い範囲に閉じ込められるケースならば閉じ込めた中でunsafeを用いたとしても効率的な型を提供すればよい
標準ライブラリにあるヒープを用いる型は全てそのようにして作られている
0721デフォルトの名無しさん
垢版 |
2022/02/04(金) 21:15:13.65ID:fCF+Tqbd
>>720
勝手訳というのがなにを指すのか不明だけどオリジナルのThe Bookからリンクされている日本語訳のことであればそれと比べている
0722デフォルトの名無しさん
垢版 |
2022/02/04(金) 21:21:32.40ID:b3SZZj/4
そんなのを見るのは極初期だけで些細な話
その後はdoc.rust-lang.orgとdocs.rsしか見ないのだから
0724デフォルトの名無しさん
垢版 |
2022/02/05(土) 14:41:30.63ID:e42LAXmg
あれは害悪レベルの訳だから初期でも見ない方がいいよ
ここでよくおかしなレスしてる人もあれの影響なんじゃないか?
0725デフォルトの名無しさん
垢版 |
2022/02/05(土) 15:12:20.92ID:WBcMnxrA
どうせ>>722のドキュメント見ないと先へ進めないしほとんどは中学生でもわかる平易な英語
日本語訳の質にこだわるような低レベルのやつはほっとけばいい
0727デフォルトの名無しさん
垢版 |
2022/02/05(土) 15:59:05.92ID:WBcMnxrA
>>726
まさにそれで最初は日本語訳でもいいがその後にthe bookを直接見るべき
そしてどの英単語でどう表現されているかを掴めば日本語訳がどうかに関わらず先へ進める
0729デフォルトの名無しさん
垢版 |
2022/02/05(土) 16:03:52.79ID:WBcMnxrA
一貫してるぞ
日本語訳の質にこだわるような低レベルのやつはほっとけばいい
これしか主張していない
0731デフォルトの名無しさん
垢版 |
2022/02/05(土) 16:22:12.93ID:XET6D0Ck
じゃあ和訳の質を話題にしている低レベルの人同士の会話はほっとけばいいのにw
0732デフォルトの名無しさん
垢版 |
2022/02/05(土) 17:02:52.76ID:VkrSTqtm
日本語イラネ言っている人は技術資料が英語でも
日本語でも生産性が変わらない人なんだよね?
アメリカの仕事でもした方が稼げるんじゃない?
0733デフォルトの名無しさん
垢版 |
2022/02/05(土) 17:05:29.47ID:nog/R4+C
和訳の質にこだわってる人たちも唯一役に立つチャンスがあるよ
それは和訳の改善案を提案して質の向上に貢献すること
しかし和訳の質にこだわってるここの人たちは批判だけで提案がないから残念な人たち
0734デフォルトの名無しさん
垢版 |
2022/02/05(土) 17:15:34.64ID:9gZgvarh
和訳の質にこだわっている人たちの質にこだわっている人は何の役にたつの?
0735デフォルトの名無しさん
垢版 |
2022/02/05(土) 17:36:04.99ID:XET6D0Ck
どこの食堂が美味いか話しているところに割り込んで、
不味い方を立て直してこいと言うくらいナンセンス。
0737デフォルトの名無しさん
垢版 |
2022/02/05(土) 17:58:18.58ID:oHTbhGZf
とはいえ元の話は
無料の炊き出しがレストランより不味い
みたいな話なのでそりゃそうだろうとしか
誰もがオライリーを気軽に買えるわけでもないし
それぞれ意味はあるだろう
0738デフォルトの名無しさん
垢版 |
2022/02/05(土) 18:14:45.46ID:9gZgvarh
ざんねんながら悪文どころか誤訳だらけで無料の炊き出しよりひどいのがままあるのが技術書の世界
0739デフォルトの名無しさん
垢版 |
2022/02/05(土) 18:19:44.18ID:nog/R4+C
>>738
誤訳だと言うなら改善案を提案して質の向上に貢献するのがいいよ
それができないなら単なるイチャモン付けるだけの残念な人
0740デフォルトの名無しさん
垢版 |
2022/02/05(土) 18:40:50.96ID:SfaxLljQ
クソ不味い飯屋にわざわざ改善案を提案するやつww
「批判するなら対案出せ」と同じアホ理論www
0741デフォルトの名無しさん
垢版 |
2022/02/05(土) 18:44:43.09ID:NEwj3nV7
両立するよ。
改善に取り組みつつ現時点では良くないところもある (信頼しすぎるな) と初心者に警告するのは何も矛盾しない。
0744デフォルトの名無しさん
垢版 |
2022/02/05(土) 19:38:56.71ID:nog/R4+C
>>743
自分は現状の和訳で問題ない派
そんな些細なことよりも和訳だけでなく原文も併用した方がよく
その後は原文だけの世界なのだから
0746デフォルトの名無しさん
垢版 |
2022/02/05(土) 19:50:42.02ID:WBcMnxrA
日本語訳の質にこだわるような低レベルのやつはその先へ行けないため日本語訳にこだわる
0748デフォルトの名無しさん
垢版 |
2022/02/05(土) 22:32:09.49ID:nog/R4+C
和訳にイチャモン付けるだけの残念な人は「複製おじさん」を連呼する人でしたか
0749デフォルトの名無しさん
垢版 |
2022/02/06(日) 10:19:03.76ID:rpYaxfPG
>>543からの流れを見ると確かに複製おじさんは英語読めないっぽいが
Copyを「所有権の複製」と思い込むのは日本語訳の質が原因ではない気がする
0750デフォルトの名無しさん
垢版 |
2022/02/06(日) 21:49:38.13ID:iA9Wv++J
そんな超初心者入門のところでもめてるのかね
trait Copyを実装している型は複製されて、実装していなかったら移動となるだけだぞ
所有権は難しくない
0752デフォルトの名無しさん
垢版 |
2022/02/06(日) 22:11:28.10ID:BkoYcqr9
>>489 の文章が間違ってる、いやおかしくない、って揉めてただけだよ
まあ気付けば普通はおかしいと思うんだけど
0754デフォルトの名無しさん
垢版 |
2022/02/06(日) 22:39:23.39ID:JXWBQEX4
>>753
複製(copy)と分岐(branching)は全く違う意味だけどCopy実装型だと所有権が複製されつつ常に分岐する??
どういう意味?
0756デフォルトの名無しさん
垢版 |
2022/02/06(日) 22:57:43.95ID:VdsOdvUM
Rustの所有権というのは権利というよりも所有しているリソースの解放義務を指している
複製できたら所有権管理の意味がない
分岐はもっと意味不明
0761デフォルトの名無しさん
垢版 |
2022/02/06(日) 23:26:57.07ID:kRmD/jh4
複製おじさん連呼する人は、もちっと具体的に指摘してくれるとありがたいんだが。
0762デフォルトの名無しさん
垢版 |
2022/02/06(日) 23:31:49.27ID:iA9Wv++J
嘘ではない
もちろんCopy実装型の時点でヒープは使われないので解放といってもスタッフ上のみだから実質何も行われない
そのためデストラクタも容認されていない
その観点からCopy実装型は所有権がないと主張する人もいるくらいだ
0763デフォルトの名無しさん
垢版 |
2022/02/06(日) 23:59:50.68ID:fxuI+J0l
>>761
おじさんを連呼してる人はスレを荒らしているだけのクズ
説明や代案や根拠などを語れない
0764デフォルトの名無しさん
垢版 |
2022/02/07(月) 00:00:24.28ID:eBqtDcmM
>>762
何も行われないのに複製されて分岐してそれ以降は異なりうるってどういうことだよ

矛盾だらけ
0766デフォルトの名無しさん
垢版 |
2022/02/07(月) 00:19:43.65ID:+QREW3s6
> そんな超初心者入門のところでもめてるのかね
> 所有権は難しくない

【超初心者向け所有権の説明】
Copy実装型は所有権が複製されて分岐してそれ以降は異なりうる

難しくないw
0767デフォルトの名無しさん
垢版 |
2022/02/07(月) 00:23:15.30ID:A0JQeUWh
>>764
この件は有名な話でRustコンパイラのサボり。
Copy型は複製分岐されて各々がdropされるのが正しいけど、スタック変数のみだからそれをサボっている。
つまり現在のコンパイラ実装は正しくなくて、dropしちゃうとサボりのせいでメモリunsafetyを引き起こす可能性がある。
だからCopy型はDropを現状では許していないという話。
rustc --explain E0184 を見てね。
0768デフォルトの名無しさん
垢版 |
2022/02/07(月) 01:29:41.70ID:6Fl/+EdH
>>767
なんか仕様と実装を混ぜて話してるけどなんで?
普通、仕様にそって実装がされるはずだけど、(この部分に関しては)実装に仕様が引きずられてるってこと?
それとも仕様通りではないってこと?
0770デフォルトの名無しさん
垢版 |
2022/02/07(月) 12:36:41.09ID:E3rdzbcC
将来実現されるであろうあるべき仕様が実装の都合で実現できていないから、それと矛盾しない範囲に仕様の範囲を制限した、という理解で良い?
0771デフォルトの名無しさん
垢版 |
2022/02/07(月) 13:38:44.35ID:ZeQEvlq1
>Copy型は複製分岐されて各々がdropされるのが正しいけど、スタック変数のみだからそれをサボっている。

まーた勝手な思い込みの妄想で嘘垂れ流してる
いい加減にしろ
0772デフォルトの名無しさん
垢版 |
2022/02/07(月) 18:29:28.92ID:lRQrpp2a
>>767
それ1.0以前の話で今とは実装も前提も全く違うからエラーメッセージ修正したほうがいいやつ

もし仮にDropかつCopyな型が実装できるようになったとしても所有権は複製されないから
0773デフォルトの名無しさん
垢版 |
2022/02/07(月) 21:58:52.41ID:pvg7UzFi
>>768
「currently disallowed」「current implementation is incorrect」「disabled for now」と強調されてるように、
あくまでも現在の実装は本来とは異なり正しくなくて、問題を引き起こすために、CopyとDropの両立を現時点では禁止してる。
理論的にはCopy型は複製分岐されて各々がdropされる形が正しくてCopyとDropの共存が可能。
この暫定的な実装に引きずられた暫定的な仕様が、将来は正される可能性も残す表現となっている。
両立禁止で実害が出てないため優先順位は低いと思われるが、もし将来に共存可能になったとしても後方互換性は生じない。

>>772
最新のエラーメッセージで合っている。
https://github.com/rust-lang/rust/blob/master/compiler/rustc_error_codes/src/error_codes/E0184.md
Latest commit 9e5f7d5 on 28 Aug 2020
0774デフォルトの名無しさん
垢版 |
2022/02/07(月) 22:27:06.61ID:zI1SZbAO
>>773
>理論的にはCopy型は複製分岐されて各々がdropされる形が正しくて
複製分岐されるのが正しいという根拠は?
0775デフォルトの名無しさん
垢版 |
2022/02/07(月) 22:38:57.39ID:pvg7UzFi
>>774
Copyなので複製分岐されるのは当たり前。
今はそこが論点ではなくて、複製分岐の後に各々に解放処理が生じるけど、現在は正しく実装されていないので仕様に制限があるとコンパイラのメッセージでも出る話。
0778デフォルトの名無しさん
垢版 |
2022/02/07(月) 23:03:21.13ID:jZIVUuZq
いつも傍から見ていてパターンがわかってきた
普通は「○○○は間違っている、×××が正しい」となるんだけど
なぜか「○○○は間違っている」だけで終わって代わりとなる対案が出てこない
>>771のように「勝手な思い込みの妄想で嘘」と否定するだけだったり
>>774のように「正しいという根拠は?」とこれも同じパターン
全てに共通するのは対案を出さずに否定ばかりしている言動
0779デフォルトの名無しさん
垢版 |
2022/02/07(月) 23:11:42.66ID:gOCxugwW
>>775
今は複製分岐されるのが本当正しいと言えるのかどうかが論点です
論点をずらさずにそう考えた根拠を示して下さい
ありませんか?
0782デフォルトの名無しさん
垢版 |
2022/02/07(月) 23:45:39.09ID:jZIVUuZq
>>779
Copyを実装している型は使われると複製され分岐すると自分も当たり前に思っているけど
異なる意見を持っているの?
否定ばかりしていて対案を出せない人はどこの世界でもダメな人扱いになっちゃうから対案を出すのがお勧め
0785デフォルトの名無しさん
垢版 |
2022/02/08(火) 00:58:18.89ID:v5+/0O15
ソケット、ファイルハンドラあたりがコピーされたらそら問題だろうからな。

>Copyを実装する型の変数にはそもそも所有権が存在しないということかな。
copyされたら所有権がないとかめちゃくちゃだな。int値だって共有されるかどうかはかなり問題だっての。
0786デフォルトの名無しさん
垢版 |
2022/02/08(火) 01:23:08.03ID:Ie+ZA5Wx
>>782 値が複製されることに異論は無いんだけど、彼は>>753などで所有権が複製されると言っていて、そこがおかしい。
0789デフォルトの名無しさん
垢版 |
2022/02/08(火) 10:46:53.27ID:VdD2swgy
複製おじさんにも唯一役に立つチャンスがあるよ
それはE0184の改善案を提案してRustの質向上に貢献することw
しかし複製おじさんは妄想だけで改善が見られないから害でしかない
0790デフォルトの名無しさん
垢版 |
2022/02/08(火) 17:39:21.77ID:L87aFEFb
複製おじさん大人気だな
個人的には「所有権が分岐する」のほうが衝撃的だった
0791デフォルトの名無しさん
垢版 |
2022/02/08(火) 18:04:38.67ID:wY99dkVo
Rustの学習してるのですが、モジュールがどう使われるものなのかいまいち想像がつきません
他の言語でいう、スタティッククラスのような使い方になるのですか?
クレート内部にはモジュールを通じてアクセスしてもらうような、アクセサーのような感覚でいいのでしょうか?
0792デフォルトの名無しさん
垢版 |
2022/02/08(火) 18:41:34.13ID:7ZuunrUW
なんで所有権が複製分岐なんていう言葉を発明しちゃうんだろな
実際に所有権をツリー構造みたいなものでイメージしてるのかな
0794デフォルトの名無しさん
垢版 |
2022/02/08(火) 20:18:25.32ID:RxI0yA8a
複製は値と所有権のペアがまるごと複製されるというイメージでわからなくもないが分岐は本当によくわからない
0795デフォルトの名無しさん
垢版 |
2022/02/08(火) 20:23:01.17ID:SvZbCMDW
>>792
何事も正しく理解できないクセがついてて
同時に、そんな自分を客観的に理解できてないから
独自用語乱発になんの違和感もないんやろな
0797デフォルトの名無しさん
垢版 |
2022/02/08(火) 20:41:11.90ID:l2NSRb44
複製おじさん自演認定連呼の人も大概だけどな
技術について語るスレなんだから個性を出すな与えるな
0798デフォルトの名無しさん
垢版 |
2022/02/08(火) 22:11:02.29ID:4v8i4qWv
変数毎のメタデータに所有権管理のためのフラグか状態変数があってその値も複製されるイメージだったんでしょ
それを匂わせることを確か書いてた気がする

仮にそういう実装だったとしてもそのメタデータ自体は所有権じゃないんだけどね
複オジは反省して分岐して欲しい
0799デフォルトの名無しさん
垢版 |
2022/02/08(火) 22:15:39.64ID:F0zgFFgG
>>784
Copyを実装する型の変数にも所有権は存在するぜ
使われるたびに複製されて別々の所有権になる
例えば借用ルールなどもそれぞれ個別に適用されるようになる
0801デフォルトの名無しさん
垢版 |
2022/02/08(火) 22:36:36.51ID:SvZbCMDW
複おじはまずコテハンかトリップつけてほしい
名無しに紛れ込んでスレ荒らすのやめてほしい
0802デフォルトの名無しさん
垢版 |
2022/02/08(火) 22:47:22.11ID:NtAny2QZ
>>799で合ってると思う私も何か勘違いしてる?
もし違うならば正しい情報を知りたい
0805デフォルトの名無しさん
垢版 |
2022/02/08(火) 23:17:16.63ID:NtAny2QZ
>>804
それそれ
おじとかオジとか言ってる人の書き込みを遡って見ても中身がないかコピペばかり
おじとオジをNGにすればよいのかな
0806はちみつ餃子 ◆8X2XSCHEME
垢版 |
2022/02/08(火) 23:24:36.35ID:d+fT+XiK
>>802
正しいよ。 >>799 で正しい。
値が複製されると同時にそれぞれが所有権を持つというのは根本的な原理そのもの。
0808デフォルトの名無しさん
垢版 |
2022/02/08(火) 23:35:38.19ID:50t+w5HT
「所有権が複製される」のではなくて、「値が複製されるとき、複製された値には新しい所有権が生まれる」と表現すべき、ってこと?
0809デフォルトの名無しさん
垢版 |
2022/02/08(火) 23:37:06.33ID:NtAny2QZ
>>806
ありがとう
おじオジ連投の人はNGにします
0812デフォルトの名無しさん
垢版 |
2022/02/09(水) 00:48:50.88ID:Th41z547
>>799,802,806
799は言葉足らずだと思う。

>>808 のがより合ってる。
0815デフォルトの名無しさん
垢版 |
2022/02/09(水) 08:16:52.91ID:RoPbijrN
論理性がない、客観性もない、実績もないのに上から目線の奴いるよね
素人相手にマウント取りたいアフィブロガーやアフィチューバーの類なんだろうけど
0817デフォルトの名無しさん
垢版 |
2022/02/09(水) 13:00:04.34ID:v0CQAsq5
所有権を実装の観点からだけ見た場合はCopy型に所有権は(設定されて)ないと考えるのは妥当
説明用の概念として見た場合はshared referenceを除くCopy実装型にも所有権があってコピーされた際にその値に対する新たな所有権が発生すると考える方が妥当

公式は基本的に後者
0818デフォルトの名無しさん
垢版 |
2022/02/09(水) 15:18:47.99ID:06jFMmW0
>>808
「所有権が複製される」という言い方は
単なる表現の問題として矮小化されるものではなく所有権という概念を根本的に誤って解釈してるのが大きな問題

それを吹聴するのはRust入門者の学びを妨害する行為なので叩かれてる
0820デフォルトの名無しさん
垢版 |
2022/02/09(水) 18:57:48.48ID:Th41z547
>>819
辞書で調べたら?
0822デフォルトの名無しさん
垢版 |
2022/02/09(水) 19:30:35.55ID:WRBpfbxt
TRPLの説明では take ownership という表現も登場するし辞書的な意味で ownership が使われているのでルールのことを指すだけではないようだ
0823デフォルトの名無しさん
垢版 |
2022/02/09(水) 19:43:45.64ID:WRBpfbxt
Each value in Rust has a variable that’s called its owner.
...
The ownership of a variable follows the same pattern every time: assigning a value to another variable moves it. When a variable that includes data on the heap goes out of scope, the value will be cleaned up by drop unless ownership of the data has been moved to another variable.

このあたりの記述を読む限り、すべての値は owner となる variabke を持つ (variable が値の ownership を有する) と表現して良いように思う

対象はすべての値なので、 Copy を実装した値にも当然 owner と ownership が存在する

なので、

let a = 1;
let b = a;

という式があった場合、aは1という値のownershipを持つし、bはaの値のコピー(1という値のコピー) のownershipを持つことになる
a の持つ ownership と b の持つ ownership の関係性をどう表現すべきか、というのが議論の対象という理解で良いかな?
0824デフォルトの名無しさん
垢版 |
2022/02/09(水) 20:01:24.42ID:WRBpfbxt
aという変数が持つ1という値とそのownershipがまとめて複製されてbに渡されると思えば、owenershipの複製という言葉も不自然ではないように思う

複製といいつつ own する値や owner となる変数が異なることに違和感を持つ人がいるのもわからんでもないが、
この構造は Box<T> の clone と同じなので、
clone を複製と呼ぶのであれば、 ownership も複製されるものとして間違いではないと思う

初学者向けの説明として適当かという議論は別途必要だとは思うけども
0825デフォルトの名無しさん
垢版 |
2022/02/09(水) 20:11:57.38ID:Sh3dorK1
それは単に値のコピーですやん
値が複製されてるだけですやん
bは複製された値のオーナーになってるだけですやん
aの所有権はどこにも複製されてないですやん
0828デフォルトの名無しさん
垢版 |
2022/02/09(水) 20:47:07.42ID:bzZIRbp2
>>824
Box<T>のcloneと同じなら
どうしてownershipも複製されることになるの?
2つの繋がりがよく分からない
0831デフォルトの名無しさん
垢版 |
2022/02/09(水) 21:22:51.45ID:DXyGa46n
所有権をCopyするって書くのをやめて、値をCopyする、にしてくれればそれで済むのに、なぜ所有権の複製を正当化しようとするのか
0832デフォルトの名無しさん
垢版 |
2022/02/09(水) 21:42:23.99ID:MYXFjZ5a
べつに値をコピせずに所有権だけコピーするとか言っているわけでもなし、そんなに問題かね?
0834デフォルトの名無しさん
垢版 |
2022/02/09(水) 21:58:09.12ID:Th41z547
>>824
だからー、値が複製されて所有権が新規にできるんだってば
0835デフォルトの名無しさん
垢版 |
2022/02/09(水) 21:58:48.91ID:p5i5ajWp
let a = 1; は値1の所有権をaが持つということ
ここでその値1の所有権を複製してしまうと、同じ値の所有権を持つ人が複数存在してしまうことになる
let b = a; で実際に起きるのは、値1のコピーとして値1'を生成し、その所有権をbに割り当てている
値1と値1'は数値としては同じに見えるとしても違う値であって
それぞれ別々に所有権がある

1'の所有権が1の所有権の複製である、という理解は
権利書をコピーして記名欄だけ書き換えるみたいな
イメージなのかもね
実際にはその記名欄が所有権の全てであって、
複製する部分というのは存在しない
0836デフォルトの名無しさん
垢版 |
2022/02/09(水) 22:01:53.64ID:pUgNKLbu
Copy実装型にも所有権はあって借用ルールに従う
そして使われる時に値と所有権は複製されて別々の値と所有権になる
そのため借用中だと複製できない
let mut a = 123;
let a1 = &mut a;
let b = a;
*a1 = 345;
println!("a={a}");
println!("b={b}");
例えばこのコードは借用中のため複製できずコンパイルエラー
0837デフォルトの名無しさん
垢版 |
2022/02/09(水) 22:02:09.07ID:p5i5ajWp
複製するという言い方は、複数の権利者が
(一時的にでも)存在し得るという理解につながるので
単に言い方の問題ではなく避けたほうがいいと思う
0838デフォルトの名無しさん
垢版 |
2022/02/09(水) 22:06:52.22ID:f/eR1VAb
どうでもいいならそれでいいんだけどね
中身の無いどうでもいい話をしましたってことで
0839デフォルトの名無しさん
垢版 |
2022/02/09(水) 22:10:36.37ID:zSJbpp9s
>>836
そういうことか!
値だけなら複製できてもよいのに
値と所有権が複製されるために借用中だと複製できないわけか
0840デフォルトの名無しさん
垢版 |
2022/02/09(水) 22:23:03.85ID:pUgNKLbu
その通り
だから「(所有権と関係なく)値が複製されて、その値に新たな所有権が生じる」よりも
「値と所有権が複製されて、別々の値と所有権になる」の方がRustを正しく理解できる
0842デフォルトの名無しさん
垢版 |
2022/02/09(水) 22:35:06.54ID:MYXFjZ5a
>>835
現実世界から借用した用語は多いけど、意味まで完全に同じとは限らないからその議論は無意味だね。
そもそも現実世界の「複製」は「同じものを新しく作ること」だしw
0843デフォルトの名無しさん
垢版 |
2022/02/09(水) 22:35:22.01ID:oiWhDOci
OwnershipのルールとReferenceのルールが整理できてないんだね
分かった気にならずに一からやり直したほうがよさげ
0845デフォルトの名無しさん
垢版 |
2022/02/09(水) 22:55:19.94ID:zSJbpp9s
>>844
僕は>>836の説明で納得した
そして実際にコンパイラエラーも確認した
君がそれを違うと言うならば
どの部分がどういう理由でどのように違うのかを皆に示さなければならないと思う
0846デフォルトの名無しさん
垢版 |
2022/02/09(水) 22:56:27.31ID:qfxIxGcm
>>836
それはmut借用中の値は使用禁止(コピーのために値を読み取るのも当然禁止)ってRustの基本ルールに違反してるってだけで
所有権の複製なんて新たな概念を持ち出す必要はないと思うが
実際エラーメッセージもそう書いてあるし
0847デフォルトの名無しさん
垢版 |
2022/02/09(水) 23:03:08.10ID:pUgNKLbu
>>846
借用中の値が使用禁止は所有権が伴っているからこそ生じるルール
だから「(所有権と関係なく)値が複製されて、その値に新たな所有権が生じる」よりも
「値と所有権が複製されて、別々の値と所有権になる」の方がRustを正しく理解できる
0848デフォルトの名無しさん
垢版 |
2022/02/09(水) 23:11:40.68ID:qfxIxGcm
複製派の人って複製元の所有権と複製先の所有権の
共通部分はなんだと考えているの?
流石に共通部分が全くなければ複製とは言わないよね?
0849デフォルトの名無しさん
垢版 |
2022/02/09(水) 23:20:26.95ID:pUgNKLbu
>>848
同じ型で複製の直後の値が同じものに対する所有権
全く異なるものに対する所有権が新たに生じるわけではない
所有権も複製されている

ちなみに現実のものに例える話はナンセンス
なぜなら現実世界では土地の所有権だけでなく土地自体も複製できないのだから
0851デフォルトの名無しさん
垢版 |
2022/02/09(水) 23:30:03.48ID:kQ1Azr/o
>>849
土地は複製できないけどそれの何が問題なの?
値として見るならCloneじゃない型と同じじゃないの?
0852デフォルトの名無しさん
垢版 |
2022/02/09(水) 23:33:43.18ID:Av5orTrB
>>848
これ知りたいね

単に引っ込みがつかなくなってるのではなく
真剣に複製されると思っているのであれば
何らか共通部分があるんだろうから
0853デフォルトの名無しさん
垢版 |
2022/02/09(水) 23:36:33.39ID:qfxIxGcm
>>849
そうすると所有権という情報には、型と値が含まれてるってこと?
その場合、値の変更は所有権の変更を伴うと考えている?
また、型と値が同じものはたくさんありうるけど、それらの所有権を区別するものはなに?
0854デフォルトの名無しさん
垢版 |
2022/02/09(水) 23:36:49.81ID:zSJbpp9s
リアルな世界では土地もその所有権も複製できないけど
こちらの世界では値も所有権も複製できる
と考えるだけで矛盾なくRustを理解できると思います
そこに矛盾はありません
0855デフォルトの名無しさん
垢版 |
2022/02/09(水) 23:38:50.10ID:IW3Xziq4
こまけえこたあ良いんだよ!! コンパイラ黙らせた奴の勝ち!!
0857デフォルトの名無しさん
垢版 |
2022/02/09(水) 23:48:17.20ID:Th41z547
>>847
>「値と所有権が複製されて、別々の値と所有権になる」
別々のものになってて複製?
言ってて変だと思わんの?
0858デフォルトの名無しさん
垢版 |
2022/02/09(水) 23:49:17.89ID:DXyGa46n
そもそも発端は入門者向けドキュメント >>486 にて、「所有権の複製(コピー)」とかいう言葉が出てきてこれではダメだ、っていうのが発端だからね
入門者向けドキュメントなんだから、正しい言葉で、正しく伝わる表現をしてほしいのよ
0859デフォルトの名無しさん
垢版 |
2022/02/09(水) 23:50:31.60ID:MsecEarl
結局のところ元の記事にあったように
「所有権とは、文字通り変数が値を所有できる権利のことです。」と間違って捉えてるってことだろうな
0863デフォルトの名無しさん
垢版 |
2022/02/10(木) 00:04:56.40ID:ERwpat+E
土地は複製できないって主張もよくわからなくて
例えばコピー機は別に原子レベルで複製しているわけでもなく
人間が見て同じに見える程度に見た目を再現してるだけなわけで
同様に土地だって同じ形状に造成できるわけじゃん

だから複製というときにはオリジナルのどこを再現したかが重要で
何が共通部分で何が差異なのかをはっきりしてほしい
0866デフォルトの名無しさん
垢版 |
2022/02/10(木) 01:01:15.29ID:ZN2u8Rs1
リソースの所有者はリソースを解放する責務がある
主としては値が変数に束縛されることで所有の関係が作られる

このへんをいろいろひっくるめて所有権の概念になるわけで、こういった概念である「所有権」そのものを複製したり作成するというのは、やはり言葉としておかしい

束縛関係を複製とか言われても意味わからん
0867デフォルトの名無しさん
垢版 |
2022/02/10(木) 01:05:28.97ID:TkQE8lES
ここで"もの"かそうでないかを区別する意味ってある?その場合の"もの"ってなに?
0868デフォルトの名無しさん
垢版 |
2022/02/10(木) 02:44:56.84ID:rtSKPHyc
所有権とは所有にまつわるルールのことというのはTRPLに書いてある通りだと思うんだが
take ownership など、所有権という物をやりとりしているように読める文言はどう解釈すれば良いんだ?
0869デフォルトの名無しさん
垢版 |
2022/02/10(木) 03:18:42.60ID:748mZL+w
所有権の話はもう禁止してくれ、唾飛ばしながら「ワイが一番所有権分かってるぞ!」とかほんまどうでもいいわ
コンピューターサイエンス学科出でもないのに、もう駄コードを書く仕事に戻れ
0870デフォルトの名無しさん
垢版 |
2022/02/10(木) 04:10:06.01ID:ZV1iYxPB
>>868 が言ってる通り公式ドキュメントと矛盾がないように書くべきでしょ
そうすると、copyするのはvalueであって、ownershipはcopyしない
ownershipはtakeしたりtransferするもの

>>866 の最初に書かれてることは良いけど、そのあとは意味不明
0871デフォルトの名無しさん
垢版 |
2022/02/10(木) 05:39:51.83ID:LZ4lXgTU
この自演おじさん、そこらじゅうで同じ芸風で荒らし回ってるから本当にタチ悪い。
0872デフォルトの名無しさん
垢版 |
2022/02/10(木) 07:56:52.23ID:B7Nnq//K
結論:
「所有権の複製」は根拠の無いオレオレ用語であり
rust公式による定義は今回も一切示されなかった

でオシマイの話
0874デフォルトの名無しさん
垢版 |
2022/02/10(木) 09:03:54.77ID:o2ECnsWv
>>870
これが正しい
0876デフォルトの名無しさん
垢版 |
2022/02/10(木) 12:39:37.06ID:JVrcL5p7
>>875
理由を言わず間違ってるとだけ指摘して勉強した方が良いとマウントとってくるいつもの人だ
反論できないから空っぽの指摘しかできないのかな
0877デフォルトの名無しさん
垢版 |
2022/02/10(木) 12:43:51.26ID:tTxcUdMu
unixのファイルシステムの権限周りの継承とかその辺とごっちゃになってんのかね?
どうして所有権をコピーみたいな話が出てきたのかわりと謎
0879デフォルトの名無しさん
垢版 |
2022/02/10(木) 16:06:58.32ID:mDz1Cqyx
>>876
説明してもらっても聞く耳持たないから
もう理由は教えないみたいなことを言われてなかったか?
0881デフォルトの名無しさん
垢版 |
2022/02/10(木) 17:36:51.53ID:jQfqixkL
所有権ルールと参照ルールを混同してたり
所有権が複製される構造はBox<T>のcloneと同じと言ってるところに
勘違いのヒントがありそうだか皆目検討がつかない
誰か解読してくれ
0886デフォルトの名無しさん
垢版 |
2022/02/10(木) 23:25:06.23ID:3aizDYBf
ここまで見てる限りどっちでもOKな話だな
値と所有権が「!Copy型は移動」「Copy型は複製」との説明でもRustの理解に支障がないのも事実
一方で現世界にない「所有権の複製」という表現に違和感を持つ人が存在することも理解できる
ただし後者はあくまでも心の内なる話だから前者を崩せない限り不利っぽい
0887デフォルトの名無しさん
垢版 |
2022/02/10(木) 23:34:31.44ID:o2ECnsWv
>>886
いや、>>870 で正しいの書いてくれてるのに、公式でもそうなってるのに何故に頑なに所有権の複製を広めようとしてるのよ笑食べて
0888デフォルトの名無しさん
垢版 |
2022/02/11(金) 00:20:49.53ID:05KWrNRV
語感には個人差があるからな
個人的には「複製」といえばCopyじゃなくCloneだし、Cloneなら「所有権の複製」もぎりぎり許せる
Copyを無理やり日本語にするなら「複写」かな

Copyの何たるかは
https://doc.rust-lang.org/std/marker/trait.Copy.html
で十分説明されてると思う

>>881
「ファイルの所有権がある⇒ファイルにアクセスできる」
の類推で
「変数(値)の所有権がある⇒変数(値)にアクセスできる」
と誤解されるケースはたまにみかける
これは用語(訳語)の問題でもあるから多少は仕方ない
0889デフォルトの名無しさん
垢版 |
2022/02/11(金) 00:26:11.55ID:jgApYu5Z
Rustの公式ドキュメントを調べると "copy of the value" という表現はたくさん出てくるが、 "copy of the ownership" のような表現は見つけられない
おそらく公式ドキュメントでも "copy of the ownership" みたいな言葉が使われそうになったときは意図的に排除されてるんだろう

もし "copy of the ownership" みたいに変更しても問題ないと思うなら、公式ドキュメントのリポジトリでそういうふうに提案してみてくれよ
Contributionのガイドを参考にコミュニティに書いたり、GithubでPull Requestするだけだからさ
https://rustc-dev-guide.rust-lang.org/contributing.html
0890デフォルトの名無しさん
垢版 |
2022/02/11(金) 01:40:58.50ID:3Ka4+NQm
ownership の take や transfer という言葉が出てくるのは !Copy な値についての説明で、
Copy な値については ownership 絡めて説明されてないよね
ownership rule 自体は全ての値に適用されるから本来は Copy な値の ownership についてとうルールが適用されるかという説明はあった方が良いかもね
元々の初学者向け記事ではTRPL英語版にない部分の説明をするにあたって所有権の複製という用語を発明したわけだけど
どう説明するとわかりやすいんだろうか
0891デフォルトの名無しさん
垢版 |
2022/02/11(金) 01:48:31.89ID:+uMSd1hh
>>886
>Rustの理解に支障がないのも事実
めちゃくちゃ支障が出てますやんw

所有権が複製されると思ってるからRustの基本ルールが理解できない >>836
所有権が複製されると思ってるからThe Bookの意味が取れない >>868
0893デフォルトの名無しさん
垢版 |
2022/02/11(金) 08:08:57.43ID:pt0GtJjK
>>890
> 元々の初学者向け記事では(中略)所有権の複製という用語を発明したわけだけど

オレオレ用語を初学者に平気で刷り込んで平気ならば

> どう説明するとわかりやすいんだろうか

今後一切あらゆる場所で説明などしないでほしい
0895デフォルトの名無しさん
垢版 |
2022/02/11(金) 08:49:57.52ID:IHS0l4KB
個人が複製を分かりやすいと思うのは自由だけど
初心者に広めるのはダメだと思うがな
もっと明らかに初心者向けの例え話とわかるような用語ならともかく
いかにも公式の技術用語っぽい見た目をしてるわけで
これを知った初心者がもっと深く知りたいと思ったときに
ググっても全く情報は出てこないし、誰かに質問しても「なにそれ?」ってなる
少なくとも公式の説明に沿った言い方なら、それで理解してる人が
大勢いるから、そういった問題は生じない
0896デフォルトの名無しさん
垢版 |
2022/02/11(金) 08:58:58.08ID:WRuOVQdn
自分の理解不足を何で公式の落ち度みたいにすり替えてるんだ。間違いを認めたら死んじゃう病なの?
0897デフォルトの名無しさん
垢版 |
2022/02/11(金) 10:27:57.19ID:2FzZhGyg
>>881
Box<T>が出てくるあたり所有権を値へのポインタ的なものとして考えてるのかもな
まあそれでも複製はされないからイミフには変わりないんだが
0900デフォルトの名無しさん
垢版 |
2022/02/11(金) 11:38:14.49ID:MSfgatap
>>808
>>「値が複製されるとき、複製された値には新しい所有権が生まれる」と表現すべき

だからそれが間違っている
値には所有権は無い
入れ物に対して所有権がある
例えば&mutはその入れ物に対する書き換え可能な参照つまり所有権の借用

>>808を肯定する連中はRustをわかっていない
0901デフォルトの名無しさん
垢版 |
2022/02/11(金) 11:42:56.32ID:UuEYjDqs
複製オジが遂に撤退戦をはじめたかw

なんで所有権が複製可能だと思い込んだのか説明してくれれば
他の人の役に立つのにな
0902デフォルトの名無しさん
垢版 |
2022/02/11(金) 12:01:57.67ID:3Ka4+NQm
>>900
「入れ物に対して所有権がある」も微妙な表現で
「入れ物となる変数が複製された値の所有権を持つ」の方が適当だと思うけど、どう思う?
0903デフォルトの名無しさん
垢版 |
2022/02/11(金) 12:06:36.51ID:IlhJUkFw
流れぶった切ってすまんけど質問
「借用」と「参照」の違いってなんなん?
0904デフォルトの名無しさん
垢版 |
2022/02/11(金) 12:07:10.38ID:MSfgatap
>>902
値は書き換わる物
だから値に所有権はない
入れ物に対して所有権がある
解放する対象も入れ物であってその値ではない
0905デフォルトの名無しさん
垢版 |
2022/02/11(金) 12:14:00.85ID:6AYXkq/G
>>904
c言語のfreeって明らかに値を解放してるように思えるんだが
freeした値はその後使えないがその値を入れていた変数はその後も使える
0907デフォルトの名無しさん
垢版 |
2022/02/11(金) 12:25:48.71ID:vAEawTbN
>>903
参照は変数の種類で、借用は参照の使い方とか参照同士の関係とか状態のこと。
明確に書かれていないけど、そのへんを意識してThe Bookのreferences and borrowingあたりを見ると良いよ。
0908デフォルトの名無しさん
垢版 |
2022/02/11(金) 12:44:48.12ID:MSfgatap
>>905
C言語のfreeでも入れ物を解放している
入れ物の中にある値を解放しているわけではない
そしてmalloc/freeで対象となる変数は入れ物を指している
つまりその変数自体は一つ階層が異なりポインタである
そのポインタ変数を書き換えても別の入れ物を指すようになるだけ
入れ物の中身が書き換わるわけではない
0909デフォルトの名無しさん
垢版 |
2022/02/11(金) 13:17:26.35ID:6AYXkq/G
>>908
いいえfreeは入れ物にある値を解放しています
入れ物を解放しているわけではありません
そもそもfreeに限らずc言語の関数はすべて値渡しなのでfree(入れ物)と書いたらfreeには入れ物にある値が複製されたのが引数として渡されて入れ物に関する情報は一切渡されません
c言語の関数が操作できるのはこの複製された値です
もし入れ物を関数funcで操作したい場合はfunc(&入れ物)と書きます
この場合も&入れ物という値が操作されます
繰り返しになりますがc言語はすべて値渡しなので決して関数に入れ物を渡して解放するなどと言った操作をすることはできません 解放されるのは値です
入れ物の参照を関数に渡すには&入れ物という表記を使いますが&入れ物も値です これは参照呼びと言われますがただの値渡しです
あなたは明らかにプログラミング初心者なのでこのレスが理解できるようになるまでこのスレには書き込まないでください
0910デフォルトの名無しさん
垢版 |
2022/02/11(金) 13:27:03.79ID:MSfgatap
>>909
それは君が抽象的なセマンティクスとポインタ等を介するコードの区別が出来ていない初心者だから理解できないのだろう
Rustではこの違いが特に大きいのでその区別を付けることが非常に重要
0911デフォルトの名無しさん
垢版 |
2022/02/11(金) 13:43:08.13ID:UrRCo2Y3
>>900
これは同意

何が何を所有してるのかという主語目的語を意識せずに
フワッと分かったつもりになってるからなんだろうね
0913デフォルトの名無しさん
垢版 |
2022/02/11(金) 14:02:29.28ID:m8Gesa51
俺は初心者なのでフワッとすら分かっておらず、このスレでは一体何が議論になっているのかよく分からない。
0914デフォルトの名無しさん
垢版 |
2022/02/11(金) 14:04:16.80ID:6AYXkq/G
>>910
別に抽象的なセマンティクスでもないよ
君が言っている「入れ物」でさえ操作的意味論的にはアドレスを表す単なる「値」として表現されていることを知るべきだね
ちゃんと理論的にはどのように定式化されているのかを知らないで入れ物だとか言った自分の無知を埋め合わすために勝手に導入したオレオレキーワード使って他の人を困らせてる辺り一向に君は初心者から脱却できないと思うよ
「入れ物」(笑)なんかじゃなくて実際に使われているテクニカルタームを使うことから始めれば?
知らないの?
0915デフォルトの名無しさん
垢版 |
2022/02/11(金) 14:05:22.34ID:6AYXkq/G
学術的に使われた用語だからテクニカルタームではないな
0917デフォルトの名無しさん
垢版 |
2022/02/11(金) 14:35:23.81ID:05KWrNRV
freeに渡すアドレス値を「入れ物」と呼ぶか「値」と呼ぶかでもめているように見える
0918デフォルトの名無しさん
垢版 |
2022/02/11(金) 14:44:41.81ID:6Qn4bKwU
>>914
その理解はおかしいよ
例えば
struct S(i32);
struct SS(i32, i32);
let i = 100;
let s = S(200);
let ss = SS(300, 400);
let a = [500, 600, 700];
この時にあなたの理解だと各変数に入っている「値」はアドレスなの?
もちろん生成コードにおいてスタック上のアドレスが用いられるのは事実だけど
Rustというプログラミング言語のレベルではそのアドレスは出てこずに抽象的に捉えるべき話でしょう
0919デフォルトの名無しさん
垢版 |
2022/02/11(金) 15:04:06.88ID:6AYXkq/G
>>918
それらの変数にはすべてそれぞれの実体が入っています
アドレスではありません
全ての「アドレス」は「値」ですがだからといって全ての「値」も「アドレス」であるとは言っていません
まずは読解力を身に着けましょう
もっと正しく理解をしましょう
0920デフォルトの名無しさん
垢版 |
2022/02/11(金) 15:18:23.74ID:6Qn4bKwU
>>919
では、あなたの主張するアドレスはどこに出てくるの?
let a = [1,2,3];
let v = vec![1,2,3];
どちらもアドレスではないですよね
0921デフォルトの名無しさん
垢版 |
2022/02/11(金) 15:28:24.64ID:6AYXkq/G
>>920
失礼しました
配列は先頭要素のアドレスが変数に格納されるでしょう
これだけで済む話です
抽象化なぞそもそも必要とされる余地はありません
0922デフォルトの名無しさん
垢版 |
2022/02/11(金) 15:36:10.19ID:H8NApfSl
所有権を持つのは値じゃなく変数
これはいいよね
オライリー本とかは少し違うけど
少なくとも公式は値が別の値を所有するとか
値が別の値の所有権を持つという考え方は採用していない

で解放のほうだけど
解放する対象はメモリ領域であって値でも変数でも無いよね
便宜的に「変数(の指してるメモリ領域)を解放する」とか
「値(が格納されてるメモリ領域)を解放する」という言い方をすることがあるだけ
0923デフォルトの名無しさん
垢版 |
2022/02/11(金) 15:46:50.29ID:MSfgatap
>>921
それも違う
配列の先頭要素のアドレスが変数に格納されているわけではない
Rustではもっと抽象的なセマンティクスでプログラミングをするし配列の長さも持つ
0924デフォルトの名無しさん
垢版 |
2022/02/11(金) 15:47:39.62ID:zZVxGVeC
値に対する所有権を変数が持つってことなら>>808は特におかしいとは思わないが?
逆に「入れ物」(変数?)に対する所有権とか言っている>>900の方が理解しにくい。
0925デフォルトの名無しさん
垢版 |
2022/02/11(金) 15:47:44.62ID:6AYXkq/G
>>922
私は操作的意味論のモデルに乗っかって表現したまでです
操作的意味論ではメモリ領域を示すアドレスは値として表現されています
ある特殊な操作的意味論で定義された理論をベースにしているRustでメモリ領域のことを値だと表現するのは間違っていないでしょう
逆に入れ物や変数だといった表現をこの文脈で使うのは言語道断かと思われます
0926デフォルトの名無しさん
垢版 |
2022/02/11(金) 15:51:44.74ID:6Qn4bKwU
>>921
それは違いますよ
そこでアドレスという考え方はしませんし、実装で見ても間違っています
例えばあなたの考えでは以下の4つの変数のうちアドレスとなるのはどれですか?
struct S(i32);
struct SSS(i32, i32, i32);
let i = 100;
let s = S(200);
let sss = SSS(300, 400, 500);
let a = [600, 700, 800];
0927デフォルトの名無しさん
垢版 |
2022/02/11(金) 15:54:42.31ID:6AYXkq/G
>>923
すいません
さらに配列の長さも保持しているのならなおさら抽象化のレベルは下がりますよね?
自分が何を言ってるのかわかっておいでですか?
もしかしてRustの抽象化レベルってCよりも下なんじゃないんですか?(笑)
0928デフォルトの名無しさん
垢版 |
2022/02/11(金) 16:01:23.79ID:VlXZAIWT
なんでこのスレでは操作的意味論とC言語とRustをちゃんぽんして語ってるの?
みんな器用だね?
0929デフォルトの名無しさん
垢版 |
2022/02/11(金) 16:02:15.20ID:6AYXkq/G
>>926
変数という用語も正しくはありません
まず第一にRustでは束縛と呼ばれます
正しく理解してください
それができないならばあなたはこれ以上スレに書き込まないでください

ちなみに私がアドレスだと言っているものはあなたが変数だと言っている物です
そもそもアドレスという表現も不適切なものですが悪しからず
0930デフォルトの名無しさん
垢版 |
2022/02/11(金) 16:21:36.51ID:MSfgatap
>>929
ついに馬脚を現したな
Rustでも変数(variable)と呼ぶことすら知らないのか
もちろん束縛(binding)も狭義の代入(assignment)と区別するために用いるが
そこでも束縛や代入の対象は変数である
0931デフォルトの名無しさん
垢版 |
2022/02/11(金) 16:32:43.51ID:6Qn4bKwU
>>929
変数という用語で合っていますよ
早く>>926の質問に答えてください
Rustでアドレスという考え方をするあなたが間違っていると明白になりますから
0932デフォルトの名無しさん
垢版 |
2022/02/11(金) 16:36:33.29ID:6AYXkq/G
>>930
Rustの用語では束縛の対象は名前です
変数ではありません
Rustが便宜的に変数と使っているのは説明のためにユーザーにRustなりに歩み寄っているからです
あなたが「入れ物」だといったよくわからないキーワードを導入したのと基本的には理由は同じです
操作的意味論では束縛の対象は変数ですが代入の対象は変数ではありません
メモリ上のある位置です
便宜的に言えばアドレスです
再三の忠告になりますが正しい理解が出来ないのであればスレに書き込まないようおすすめします
0933デフォルトの名無しさん
垢版 |
2022/02/11(金) 16:45:09.37ID:6AYXkq/G
>>931
i,s,sss,aがアドレスです
まずは>>929を理解する読解力を身に着けてください
> Rustでアドレスという考え方をするあなたが間違っていると明白になりますから

逆にアドレスという考え方をしないのですか?(笑)
手続き型言語の重要な機能ですよ?
ocamlなどと言った非純粋な関数型言語にすらありますが(笑)
アドレスという考え方を他の言語利用者が使うのを許せないのであればこの機能がないHaskellなどをご利用してくださいとしか・・・(笑)(笑)(笑)
Rustには触れないでくださいね😂
0935デフォルトの名無しさん
垢版 |
2022/02/11(金) 16:56:53.29ID:6AYXkq/G
>>934
変数i,s,sss,aにアドレスが入っているなどと言ってません
読解力も理解力もないんですね
i,s,sss,aは変数ではなくてアドレスという名の値だって言うことを理解できないとあなたはいつまで立っても初心者のままですよ??(笑)
0936デフォルトの名無しさん
垢版 |
2022/02/11(金) 16:59:09.28ID:6AYXkq/G
>>934
間違っているのはあなたです
これで明白になりました
0939デフォルトの名無しさん
垢版 |
2022/02/11(金) 17:07:13.91ID:6Qn4bKwU
ID:6AYXkq/G氏は
>>919で「それらの変数にはすべてそれぞれの実体が入っています アドレスではありません」
>>921で「失礼しました 配列は先頭要素のアドレスが変数に格納されるでしょう」
これで全く理解できていないことが露呈してからさらに暴走中ですね

>>935
Rustにおいてそれらの変数i,s,sss,aはアドレスではありません
抽象的な考えが苦手ですか?
0941デフォルトの名無しさん
垢版 |
2022/02/11(金) 17:19:13.64ID:6AYXkq/G
>>939
Rustを含めアドレスという言語機能を持っている手続き型言語で変数と呼ばれているものはただのアドレスです
Rustでいう値が束縛された名前は操作的意味論における変数に対応していてあなた方がいう変数とは操作的意味論におけるアドレスを表現するものの対応物です
本来変数とアドレスは同義のものでc言語の規格で完全にポインタとアドレスが同じものとして扱われ区別されないのと同様に区別する必要性がないものです
現にポインタもアドレスも変数も操作的意味論では区別されていません
このあたりを理解できない限りID:6Qn4bKwUは永遠に初心者のままのようだ🤣
0942デフォルトの名無しさん
垢版 |
2022/02/11(金) 17:26:17.96ID:7ybYem6W
cのfreeは値「で」解放してるだけなんだけどなw
int *p = malloc(sizeof(int)); // 仮に p = 0x5617ae143260とする
free((int *)0x5617ae143260); // 値でfreeできる

値をfreeしてるわけでもなく
入れ物を解放してるわけでもなく
値をfreeに与えてやってあとはむこうでうまくヒープを解放してくれる
ヒープ解放のきっかけを値で指定してるだけ
0944デフォルトの名無しさん
垢版 |
2022/02/11(金) 17:42:17.21ID:VlXZAIWT
>>941
横レスだけど
仮にこの世にコンパイラも実行するマシンもなくて、Rustのコードだけが紙に書かれてたとして
それでもi,s,sss,aは変数ではなく、アドレスという名の値だって言い張るの?
具体的にはどういう値なの?
0945デフォルトの名無しさん
垢版 |
2022/02/11(金) 17:45:23.35ID:6AYXkq/G
>>944
さあ?
実行するマシンが決まっているなら値はなんでもいいんじゃないんですか?
それこそ文字でも記号でもなんでもいい
その辺りの議論は操作的意味論の教科書で論じられていますよ
0946デフォルトの名無しさん
垢版 |
2022/02/11(金) 17:45:40.46ID:6AYXkq/G
決まっていないなら
0947デフォルトの名無しさん
垢版 |
2022/02/11(金) 17:56:17.41ID:VlXZAIWT
>>945
なんでもいいの?
書かれているコードが>>926だとして、
iの値が0x5617ae143260で
aの値が0x5617ae143260でもあなた的には問題ないってこと?
0948デフォルトの名無しさん
垢版 |
2022/02/11(金) 18:02:50.44ID:6AYXkq/G
>>947
新しいアドレスにはすでに使われているアドレスの値を使ってはいけないという制約は操作的意味論でも目にするでしょう
あなたが熱心に勉強するタイプの人であったなら私のレスを待たずにして自分で調べて自分で疑問を解決していただろうに残念ながらあなたは受動的にしか学習せず一生初心者のままに留まる人間なんでしょうね
0949デフォルトの名無しさん
垢版 |
2022/02/11(金) 18:14:14.82ID:6Qn4bKwU
>>942
その通りで、単なる識別子としての「値」で解放しているだけだね
そしてアロケーションライブラリによってはその「値」がアドレス自体でないかもしれない、と
C言語では抽象レベルと具体化レベルがほぼ一致のためアドレスが使われアドレスで考えてもいいけど
多くのプログラミング言語ではその部分は実装レベルに隠蔽されているからアドレスで考えてはよくないね

で、話を戻すと、大元の話ではその「『値で』解放している」かどうかではなくて
「『値を』解放している」のか、「なんらか抽象的な『空間を』解放しているのか」の話だったと認識してる
0950デフォルトの名無しさん
垢版 |
2022/02/11(金) 18:27:09.56ID:VlXZAIWT
>>948
ごめん、プログラミング歴20年超えてるんだわ

まあ>>947は意地悪だったけど、何が言いたいかっていうと、
有効なアドレスってのは実行時するかコンパイルしないことには定まらないでしょって話
でも言語仕様っていうのは、コンパイラが存在しなかったとしても存在し得るんだわ

で、他の人は言語仕様の話をしてるけど、一人だけ変数じゃなくてアドレスという値だって言い張るから、
マシンが存在しない状態だとどういう値なのよ?って思ったのね
意地悪なこと書いてごめんよ
0951デフォルトの名無しさん
垢版 |
2022/02/11(金) 18:35:25.52ID:7ybYem6W
おまえらって基本マジメなんやろな何か
意見の違いはあれどそんなに嫌いじゃないわ
(ただし複製おじは除く)
0953デフォルトの名無しさん
垢版 |
2022/02/11(金) 18:39:18.92ID:6AYXkq/G
>>949
closeシステムコールはfile descriptorをcloseする
file descriptorでcloseするとは誰も言わない
file descriptorはファイルを参照する値であるがファイル自体ではない
それと同様freeはアドレスという値を解放しているのであってアドレスという値で解放してるとは誰も言わない
「値で解放するの表現が正しい」(笑)って言う意見に耳を傾けるのはまだあなたが初心者を脱することができていない証拠

https://linuxjm.osdn.jp/html/LDP_man-pages/man2/close.2.html
こういうサイトにも「close() は、ファイルディスクリプターをクローズする。」 とある
0954デフォルトの名無しさん
垢版 |
2022/02/11(金) 18:51:10.18ID:XGwZjA15
>>951
真面目すぎてひねくれたパターンだろうな
出世もしないで片隅でコード書いてる人よくいるし
0955デフォルトの名無しさん
垢版 |
2022/02/11(金) 18:51:59.28ID:6Qn4bKwU
>>952
その最適化で消えるようなもんが言語仕様
例えばRustでは言語仕様で通常の参照ポインタはnullにならない
nullを言語仕様として扱わずNone値を持つOptionを導入にしている
そしてヌルポの先へアクセスすることを完全に封じている、というのが言語仕様

ところがその抽象レベルを離れて実装レベルになると話が違う
愚直にOptionを実装すると参照ポインタ以外にメモリを余分に使う
そこで最適化によってNone時は参照ポインタの実体アドレスを0すなわちnullポインタとしている
これでOption分の余分なメモリを使わずに済ませている

つまり言語仕様としての抽象化されたレベルと
実際にアドレスがどうなるかという具体化されたレベルは常に区別しないといけない
Rustプログラマーとしては実装でどうなるかは知らなくてもプログラミングできる
そしてまずはその抽象的なレベルのみ意識して学習すべき
0957デフォルトの名無しさん
垢版 |
2022/02/11(金) 21:48:20.48ID:Q/4j6JIT
>>925
まーたオジさんいい加減なこと書いてるねw
操作的意味論ではvariableとlocationとvalueを明確に区別するのが一般的
メモリ領域のことを値だと表現するのはRust的にも操作意味論的にも間違い
0958デフォルトの名無しさん
垢版 |
2022/02/11(金) 21:52:44.45ID:38j0NNSx
>>941
>Rustを含めアドレスという言語機能を持っている手続き型言語で変数と呼ばれているものはただのアドレスです

全く違うんですけどwww
都合悪くなってスレ流したいのかもしれないが
とりあえず嘘八百でスレ埋め立てるの辞めてくれ
0959デフォルトの名無しさん
垢版 |
2022/02/11(金) 22:35:25.65ID:6AYXkq/G
>>957
操作的意味論ではそれ以上簡約できない項を値と呼びます
varもlocもどちらもそれ以上簡約できないので値です
試しにTaPLで値ががどのようにBNFで帰納的定義されている集合なのか確認してみたら?
あなたが理解していないだけでは?
0960デフォルトの名無しさん
垢版 |
2022/02/11(金) 22:39:32.55ID:6AYXkq/G
>>958
スレ埋めてるのはどちらかというとこのような無意味なレスをするあなたでは?
私は自分のレスが正しいと知っておりますのでどうぞ余計なレスを書き込まないでこのスレを延命してくださいませ
0961デフォルトの名無しさん
垢版 |
2022/02/11(金) 22:48:24.70ID:6Qn4bKwU
6AYXkq/Gを相手にしても無駄だから元の話に戻りましょう
>>808について自分の意見は
○「型のインスタンスに所有権がある」
×「値に所有権がある」 ←値は途中で完全に置き変わっても構わないため×
×「変数に所有権がある」 ←変数はどんどん移動できて一時的な束縛にすぎないため×
×「アドレスに所有権がある」 ←アドレスは関数へ渡したり返したり途中で変わるため×
0962デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:10:21.43ID:g7TOVgtJ
>>961
「所有権がある」という意味が「所有権を持つ」という意味であれば
「値の所有者は変数」だから「所有権を持つのは変数」だよ
スコープを抜ける時に所有リソースを解放する責任というのかownershipを持つということ

型のインスタンス?
説明してもらわないと意味分からないな
0963デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:19:43.49ID:rRV0mw3H
>>961
> 値は途中で完全に置き変わっても構わないため

所有権というのは「後始末する責任」のこと。
内容が書き換えられることを許すのは所有権を手放しているわけではない。
0964デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:22:41.86ID:jgApYu5Z
>>961
> 「変数に所有権がある」 ←変数はどんどん移動できて一時的な束縛にすぎないため×
変数は移動できなくない? 何か別のことを言いたかったんかな?

変数が所有権を持つ、で良いんじゃないかな
値を変数に束縛するときに、変数が値を所有することになる
そして変数が値を所有したままスコープアウトすると、値をdrop(解放)する
0966デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:27:09.03ID:6Qn4bKwU
主語と目的語を逆に違う意味に誤解されるとわかったので補足します
○「型のインスタンスに対して所有権があるor生じる」
×「値に対して所有権があるor生じる」 ←値は途中で完全に置き変わっても構わないため×
×「変数に対して所有権があるor生じる」 ←変数はどんどん移動できて一時的な束縛にすぎないため×
×「アドレスに対して所有権があるor生じる」 ←アドレスは関数へ渡したり返したり途中で変わるため×

>>962
プログラミング言語の分野で一般的に用いられるインスタンスです
型とインスタンスは一般的に1対多の関係になります (シングルトンでは1対1ですが)
言語によっては型をクラスと表現する場合もあるようですがRustではそんな狭い範囲ではなく全ての型が対象です

>>963
そのように値は変わっていくものだから
値に対して所有権といっても曖昧さが残るでしょう
だから不変でない値に対して所有権があるとの考えはよろしくない
まだ>>964の言う変数を持ち出したほうがマシ

しかし変数との関係は一時的にすぎず所有権は別の変数へ移動していきます
所有権と常に1対1の関係にあるのは(型の)インスタンスです
0967デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:32:51.77ID:rRV0mw3H
>>964
変数が所有権を持つというのは変な解釈。
結果的にはそういう挙動ではあるんだが
値が変数に捉えられている間は寿命が継続されるというルールによって
変数のスコープと連動してるだけ。
所有権を持っているのはあくまで値。
0968デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:37:03.65ID:6Qn4bKwU
>>967
所有権を持っているのはインスタンスであって
値はそのときどきで変化するだけにすぎない存在だと思います
0970デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:45:01.94ID:MSfgatap
俺が入れ物に対して所有権があると>>900で書いたのも実質その型のインスタンスだ
インスタンスという言葉を使うと面倒になりそうなので抽象的に型の入れ物とした
いずれにせよ所有権の対象は値ではなく値が収容される入れ物orインスタンスだ
0971デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:45:21.67ID:rRV0mw3H
実際のところ「値」と「インスタンス」の間にそんなに意味の差はないです。
特的の型を元に作られたということを強調するときにインスタンスと言うことはありますが、
どの値も型を持つのでインスタンスではない値などありはしません。
0972デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:47:31.44ID:6Qn4bKwU
>>971
インスタンスはその型の形をした器(うつわ)であり解放されるまで不変
値はその器(うつわ)に入った内容にすぎず可変
0974デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:49:47.15ID:3qua/k5E
>>967
>所有権を持っているのはあくまで値。

で、その値は何の所有権を持ってるのさ?
0975964
垢版 |
2022/02/11(金) 23:51:18.52ID:jgApYu5Z
そもそも「所有権を持つ」ってのが苦しい
英訳すると "own the ownership" になってしまうが、そんな表現は公式ドキュメントでも避けられてるように思う

値が変数に束縛されるとき、その値を変数が所有することになる
変数をreturnしたり、変数を他の変数に代入するときには、所有権がtransferされることになる

ここまでは良いでしょ
例えば、公式ドキュメントにもこう書かれてる
https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html
> Returning values can also transfer ownership.

なので、強いて >>961 の中から選ぶなら変数が所有権を持つだけど、最初に書いたようにそもそも「所有権を持つ」が苦しいので、
「変数が値を所有する」とすれば良いと思う
0976デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:51:21.22ID:3qua/k5E
>>965
>「変数が値を所有する」

これが正解。
0977デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:51:57.38ID:MSfgatap
>>973
皆がその点については定義がはっきりしないからこれだけ揉めてるんだろ
「そんな定義はないです」は反論にすらなっていない
0978964
垢版 |
2022/02/11(金) 23:53:29.17ID:jgApYu5Z
ああ、別に「持つ」を必ずしも "own" で訳す必要もないね
さっきから変なことばかり書いててすまんね、今日は冷静になっていったんもう寝る
0979デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:54:02.65ID:rRV0mw3H
>>974
値自身を後始末する責任をもってる。
所有権という訳語がよくないというのはよく指摘されることだが、
何者かが値を所有しているという誤解のもとになるからだ。

変数が所有権を持っていることにしたら
一時オブジェクトの所有権はどうなってんだって話になるだろ。
0980デフォルトの名無しさん
垢版 |
2022/02/11(金) 23:57:48.33ID:6Qn4bKwU
>>975 >>976
そんな話は誰もしていないと思う
所有権は何に対して付随するのか生じているのかが論点
そして所有権が消滅するのは型のインスタンスが最後に解放される時
だから所有権と1対1の関係にあるのは(型の)インスタンスだと主張しています
0981デフォルトの名無しさん
垢版 |
2022/02/12(土) 00:03:26.33ID:mURtvSsP
>>972
> インスタンスはその型の形をした器(うつわ)であり解放されるまで不変

いいえ。
代入で内容が書き換えられる場合もあり、
そのときに drop が呼ばれます。
寿命の管理は値に付随します。
0982デフォルトの名無しさん
垢版 |
2022/02/12(土) 00:19:59.58ID:kNBFVDwU
とりあえずbookの
4.1. What is ownership?
(ttps://doc.rust-lang.org/book/ch04-01-what-is-ownership.html)
からOwnership Rulesの節を丸ごと抜いてきた(訳は適当)


Ownership Rules

First, let’s take a look at the ownership rules.
Keep these rules in mind as we work through the examples that illustrate them:

* Each value in Rust has a variable that’s called its owner.
* There can only be one owner at a time.
* When the owner goes out of scope, the value will be dropped.


まずは所有権(ownership)に関するルールを見てみよう
このルールを記憶に留めて以下の例示を読み進めてほしい

・Rustの各々の値(value)は所有者(owner)と呼ばれる1つの変数(variable)をもつ
・所有者は同時に1つしか存在しない
・その所有者がスコープからいなくなる時、その値は破棄される
0983デフォルトの名無しさん
垢版 |
2022/02/12(土) 00:26:03.97ID:lHDa3hl7
>>982
これが正解
0984デフォルトの名無しさん
垢版 |
2022/02/12(土) 00:26:42.42ID:/iL1/Dd6
>>981
内容が書き換えられてdropすることはない
所有権と値は関係ない
値に付随するものではない

>>982に明記されているように所有権を持つ所有者は変数
所有者である変数がスコープから外れるとdrop
0986デフォルトの名無しさん
垢版 |
2022/02/12(土) 00:37:10.88ID:/iL1/Dd6
インスタンスというのも一理ある
その型のインスタンスが作られてから解放されるまで一貫して一つの存在なのに対して
変数は次々と移り変わって行く乗り物と捉えることができる
そしてインスタンスがたまたま束縛されている変数がスコープから消えると乗っていたインスタンスも巻き添えで消えると考えられないこともない
0990デフォルトの名無しさん
垢版 |
2022/02/12(土) 01:58:18.50ID:eWE5dZha
横からすまんが、実際のメモリ上だと所有権ってどうなってるもんなの?
>>982にある仕組みからしたら・・・・メモリが確保されるのと同時に、併せて所有権情報(スタックへの参照か何か?)がメモリのどっか確保されるわけ?
俺、てっきりコンパイラへのただの指示だとばっか思ってたぜ
0991デフォルトの名無しさん
垢版 |
2022/02/12(土) 02:19:56.25ID:dWh4TlR2
横からキターーー

コンパイラの課すルールの話なので
所有権情報が実行時にメモリに確保されたりしないよ
0992デフォルトの名無しさん
垢版 |
2022/02/12(土) 04:01:34.21ID:tNCVqmWf
まじか、そうなんだ
0994デフォルトの名無しさん
垢版 |
2022/02/12(土) 07:47:32.16ID:XghCcbPA
struct S;
impl Drop for S {
fn drop(&mut self) {
println!("drop");
}
}
fn main() {
S;
}
↑じゃあこれは何が所有権をもってて何がdropさせてんの?
インスタンス説のほうがまだシックリくる?
変数も所有権を持てるしスコープ終了で手放せる?
0995デフォルトの名無しさん
垢版 |
2022/02/12(土) 08:42:47.12ID:4ZF6L5uh
>>961
お前が突っかかって来たんだろうが
ガイジwwww
0996デフォルトの名無しさん
垢版 |
2022/02/12(土) 08:42:55.77ID:4ZF6L5uh
うんこ
0997デフォルトの名無しさん
垢版 |
2022/02/12(土) 08:43:01.75ID:4ZF6L5uh
まんげ
0998デフォルトの名無しさん
垢版 |
2022/02/12(土) 08:43:06.69ID:4ZF6L5uh
ちんげ
0999デフォルトの名無しさん
垢版 |
2022/02/12(土) 08:43:39.79ID:4ZF6L5uh
>>957
お前の負けやでwwwwwwww
1000デフォルトの名無しさん
垢版 |
2022/02/12(土) 08:44:18.55ID:4ZF6L5uh
無教養のガイジども阿鼻叫喚していて草wっwr
ンゴwwwwwww
10011001
垢版 |
Over 1000Thread
このスレッドは1000を超えました。
新しいスレッドを立ててください。
life time: 96日 22時間 39分 19秒
10021002
垢版 |
Over 1000Thread
5ちゃんねるの運営はプレミアム会員の皆さまに支えられています。
運営にご協力お願いいたします。


───────────────────
《プレミアム会員の主な特典》
★ 5ちゃんねる専用ブラウザからの広告除去
★ 5ちゃんねるの過去ログを取得
★ 書き込み規制の緩和
───────────────────

会員登録には個人情報は一切必要ありません。
月300円から匿名でご購入いただけます。

▼ プレミアム会員登録はこちら ▼
https://premium.5ch.net/

▼ 浪人ログインはこちら ▼
https://login.5ch.net/login.php
レス数が1000を超えています。これ以上書き込みはできません。

ニューススポーツなんでも実況