Rust part26

レス数が1000を超えています。これ以上書き込みはできません。
1デフォルトの名無しさん
垢版 |
2024/09/20(金) 22:18:38.38ID:c48cFuZJ
公式
https://www.rust-lang.org/
https://blog.rust-lang.org/
https://github.com/rust-lang/rust

公式ドキュメント
https://www.rust-lang.org/learn

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

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

※Rustを学ぶ際に犯しがちな12の過ち
https://dystroy.org/blog/how-not-to-learn-rust

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

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

前スレ
Rust part25
https://mevius.5ch.net/test/read.cgi/tech/1722354386/

ワッチョイスレ
プログラミング言語 Rust 4【ワッチョイ】
https://mevius.5ch.net/test/read.cgi/tech/1514107621/
2024/11/22(金) 18:39:10.11ID:y0TICFrd
そのキーワードをunsafeではなく「ハイリスクハイリターン」にでも
変えれば生霊が成仏するような気がする
リスクを100倍にすればリターンも100倍になるってのはただの物語にすぎないと個人的に思うが
科学だと思ってる人間がいても別に驚かない
2024/11/22(金) 18:50:58.98ID:MEPFF+NK
>>882
C/C++/Rustのオーバーヘッドは同じ
メモリ管理もポインタで別主体の複数箇所から指すならC++のshared_ptrやRustのRc/ArcのようにCでも参照カウンタを持つしか安全に解放できない
938デフォルトの名無しさん
垢版 |
2024/11/22(金) 22:18:31.82ID:TcJB6S+5
>>935
部分借用のケースあるじゃん
スレッド1がバイト列の前半を、スレッド2が後半を書き換える場合
これは理屈上はロックが要らないけどsafe Rustだとルール上ロックが要るケース
2024/11/22(金) 22:39:33.83ID:y0TICFrd
a 形式だけで安全といえる
b 中身をよく見れば安全といえる
c 形式も中身も危険

unsafeの部分はbとcが混ざっている
(bの価値がaより高いとは言ってないし安いとも言ってない)
2024/11/23(土) 06:30:53.82ID:phMWL2Cw
>>938
Rustでもロックは不要
例えばバッファをエリア8分割して8つのスレッドで書き換え並列処理

use rayon::prelude::*;

const BUF_SIZE: usize = 1 << 16;
const NUM_OF_AREA: usize = 8;
const AREA_SIZE: usize = BUF_SIZE / NUM_OF_AREA;

fn main() {
let mut buf: Box<[i64]> = (0..BUF_SIZE as i64).collect();

buf.par_chunks_mut(AREA_SIZE).for_each(|area| {
println!("DEBUG: {:?}", std::thread::current().id());
area.iter_mut().for_each(|n| {
*n = *n * *n;
});
});
}
941デフォルトの名無しさん
垢版 |
2024/11/23(土) 10:31:17.67ID:ljLqVKjZ
外部クレートな上にイテレーターにしか使えないものでしょ
例えばこんな構造体

struct {
 a: Vec<u8>,
 b: Vec<u32>,
}

に対してスレッド1と2がそれぞれaとbを操作する場合は?とか、メモリ的に連続しないものを扱う場合は?とか、回避できないものはある
(後者は例えば、4動画を並列に処理し、それを上下左右に並べた1つの動画にする場合)

元のレスの「Rustでロックが必要なケースはC言語でも必要」という主張は必ずしもそうでない
(総合的には事故を防げるメリットの方が大きいし、「必要な場合のみunsafeを使う」というRustの方が良いと思ってるので、言語に対する批判ではないと思って欲しい)
2024/11/23(土) 11:04:40.44ID:AT4bo2Ti
RustでもCでもロックが不要な例を出してはいけない

また「Cでは不要」の部分だけを自分で検証して残りは他責にするのは
近似としては悪くないが厳密には悪い
2024/11/23(土) 14:25:42.64ID:ZNzlTdzo
struct Test {
a: UnsafeCell<Vec<i32>>,
b: UnsafeCell<Vec<i32>>
}

// 手動でスレッドセーフであることを宣言
unsafe impl Sync for Test {}

impl Test {
fn new() -> Self {
Test {
a: UnsafeCell::new(Vec::new()),
b: UnsafeCell::new(Vec::new())
}
}
fn get_a(&self) -> &mut Vec<i32> {
unsafe { &mut *self.a.get() }
}
fn get_b(&self) -> &mut Vec<i32> {
unsafe { &mut *self.b.get() }
}
}
2024/11/23(土) 14:28:48.33ID:ZNzlTdzo
使う側はこんな感じ。

fn main() {
let test = Test::new();

// 2つのスレッドで別々のフィールドにアクセス
std::thread::scope(|scope| {
scope.spawn(|| {
let a = test.get_a();
a.push(1);
});

scope.spawn(|| {
let b = test.get_b();
b.push(2);
});
});
}
2024/11/23(土) 14:37:46.12ID:ZNzlTdzo
c++はunsafeの部分を区別せずにやっちゃってるだけで、危険性があるのは変わらんのよ。rustの場合そこが明示的になってる分分かり易いというだけ。
2024/11/23(土) 17:18:14.36ID:iTmIV0ch
>>943
これsafeにしたらダメでしょ
2024/11/23(土) 17:57:14.51ID:AT4bo2Ti
その石ころはパンに変化しなかった
はい論破
人は論破のために生きる
2024/11/23(土) 18:44:09.87ID:phMWL2Cw
>>941
それならrayonを使うまでもないけど
使えばシンプルにこう書ける

struct Foo {
a: Vec<u8>,
b: Vec<u32>,
}

fn main() {
let mut foo = Foo {
a: vec![1, 2, 3],
b: vec![11, 22, 33],
};

rayon::join(
|| {
println!("DEBUG: a: {:?}", std::thread::current().id());
foo.a.push(4);
},
|| {
println!("DEBUG: b: {:?}", std::thread::current().id());
foo.b.push(44);
},
);

assert_eq!(foo.a, [1, 2, 3, 4]);
assert_eq!(foo.b, [11, 22, 33, 44]);
}
2024/11/23(土) 18:47:58.14ID:phMWL2Cw
>>948をrayonを使わずに書くと

std::thread::scope(|scope| {
scope.spawn(|| {
println!("DEBUG: a: {:?}", std::thread::current().id());
foo.a.push(4);
});
scope.spawn(|| {
println!("DEBUG: b: {:?}", std::thread::current().id());
foo.b.push(44);
});
});

>>943
そんなことしなくても大丈夫
2024/11/23(土) 20:57:00.22ID:h7mzZyhg
>>948
フィールドが可視なこと前提にしちゃっていいの?
2024/11/23(土) 21:58:14.47ID:phMWL2Cw
>>950
そんな話までやるの?
どの言語でも同じ
必要なアクセスメソッドを用意するだけ

impl Foo {
pub fn new(a: Vec<u8>, b: Vec<u32>) -> Self {
Foo { a, b }
}
pub fn a_and_b_mut(&mut self) -> (&mut Vec<u8>, &mut Vec<u32>) {
(&mut self.a, &mut self.b)
}
}
2024/11/23(土) 22:17:13.62ID:h7mzZyhg
>>951
>>941が言ってるのは外部クレートの構造体で可視性にしろメソッドにしろ勝手にいじれないって前提での話だと理解してたんだけど
違うの?
2024/11/23(土) 22:29:09.24ID:wvnRoJ4J
>>952
可視もアクセスもない外部の構造体のフィールドを!
フィールド毎に別スレッドで並列に書き換えたい!
ってことかよ
ワロタ

>>941もそこまでバカげた無茶を求めてない
求めてることは既に解決しただろう
2024/11/24(日) 01:29:38.03ID:4sDepkd+
スライスの内部を弄るのはunsafeだけど
その構造体の内部は安心安全だからunsafeがどこにも現れないんだな
2024/11/24(日) 01:59:38.19ID:J3183MXo
Vectorの標準機能
好きなところで2分割する方法
スレッドでま利用可能

fn main() {
let mut vec = vec![1, 2, 3, 4, 5, 6];
let mid = vec.len() / 2;
let (left, right) = vec.split_at_mut(mid);

println!("left: {:?}", left); // [1, 2, 3]
println!("right: {:?}", right); // [4, 5, 6]

// 両方のスライスを同時に変更可能
left[0] = 10;
right[0] = 40;

println!("vec: {:?}", vec); // [10, 2, 3, 40, 5, 6]
}
2024/11/24(日) 02:07:14.81ID:J3183MXo
vecの機能
chunks_mutを使用する方法(等分割)
指定したサイズで複数個のスライスの可変参照

fn main() {
let mut vec = vec![1, 2, 3, 4, 5, 6];
let mut chunks = vec.chunks_mut(vec.len() / 2);

if let (Some(left), Some(right)) = (chunks.next(), chunks.next()) {
println!("left: {:?}", left); // [1, 2, 3]
println!("right: {:?}", right); // [4, 5, 6]

left[0] = 10;
right[0] = 40;
}

println!("vec: {:?}", vec); // [10, 2, 3, 40, 5, 6]
}
957デフォルトの名無しさん
垢版 |
2024/11/24(日) 17:24:11.96ID:0kQqDut1
Rustで書いたら危険だけどCなら安全に書ける例を教えてくれ
2024/11/24(日) 18:13:55.87ID:I2rtYfjq
>>941
rayonは確かに標準ではなく外部だが
C/C++では今も作り出せていないrayonやtokioなどの基盤ライブラリを
Rustが生み出すことができた勝因は
標準ライブラリを最小限にして外部のクレートに多くを託す方針をとったため

それでもなお標準ライブラリだけに拘るならば
その>>940の例はrayonを使わずに以下のように書くことができる

std::thread::scope(|scope| {
let mut rest: &mut [i64] = &mut buf;
while let Some((area, new_rest)) = rest.split_at_mut_checked(AREA_SIZE) {
rest = new_rest;
scope.spawn(|| {
area.iter_mut().for_each(|n| {
*n = f(*n);
});
});
}
});
2024/11/24(日) 18:18:22.12ID:ZV7M8h6P
rayonってCから使えないの?

最近はたまにCから呼び出せるようにしたRustのクレートを見かけるよな
以前とは逆向きだ
960デフォルトの名無しさん
垢版 |
2024/11/25(月) 09:33:08.05ID:SsaYg1Am
科学 + ンニュース 5ch

保守派もリベラル派も「自分の政治的信念に合致したニュース」を信じやすいという研究結果 [すらいむ★]
https://itest.5ch.net/egg/test/read.cgi/scienceplus/1732447647

コメントも含めて読むと
陰謀論が収まら無い理由が判明する
961デフォルトの名無しさん
垢版 |
2024/11/25(月) 15:15:08.59ID:TQeBxjwA
>>957
Rustは安全なものでもunsafe付けたら危険になる言語
2024/11/25(月) 17:19:35.66ID:HD3K11z8
>>958
結局、全体の可変参照&mutがある時
・structは各フィールドの&mutを同時に安全に得られる
・スライスはsplit_at_mut_checkedで任意に分割したサブスライスの&mutを同時に安全に得られる
つまりunsafeの必要なく安全に同時に書き換え可能ということだね
2024/11/25(月) 17:20:53.69ID:HD3K11z8
>>961
unsafeは危険という意味ではなくて
C/C++と同じようにプログラマーがその部分のコードの安全性の責務を持ちなさい、という意味だよ
もしそれを危険と呼ぶならC/C++のコードは常に全てが危険
2024/11/25(月) 17:46:18.55ID:VupnR4Dz
よくrustと他の言語で比較するときに条件を揃えてないのが多すぎる印象。
パフォーマンスで差が出る部分でHashMapがある。デフォルトのハッシュ関数が安全に振られてるからちょっと遅い。高速化するなら下記のような感じ。

use std::hash::BuildHasherDefault;
use std::collections::HashMap;
use rustc_hash::FxHasher; // より高速なハッシュ関数

// FxHasherを使用したHashMap
type FastMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;

fn main() {
// 高速なハッシュマップの作成
let mut fast_map: FastMap<i32, String> = FastMap::default();
fast_map.insert(1, "fast".to_string());
}
2024/11/25(月) 17:55:45.25ID:VupnR4Dz
昔、PHPでHashDos攻撃でサーバーが止まるという問題があった。特定のハッシュ値を生成するようなパターンで速度が著しく低下する。なので今はwebで外部からデーターが送られて来る時は安全なハッシュ関数を使う。
このハッシュが安全かどうかで処理速度が変わるのだけど、他の言語では昔のままのが多い。それでrustとC++を比較して遅いとか言われる事がある。安全か速度か選べるから両方揃えて比較してくれ。
966デフォルトの名無しさん
垢版 |
2024/11/25(月) 18:58:14.92ID:1VAZLaev
FxHash使うと結構速度変わるんだよな
967デフォルトの名無しさん
垢版 |
2024/11/26(火) 10:38:32.10ID:OrSHBPPk
rustとかでi32とかVecとかHashMapとかにmethodを勝手にimplして使うことについて問題とかないですか?
2024/11/26(火) 10:56:47.14ID:+wgmkm+f
coherenceの縛りがあるから勝手にimplすることはできない
2024/11/26(火) 11:04:59.40ID:MMcFc6BZ
なんらかの trait を impl するという意味なら好きなようにやって構わないが、複数の型に impl する必要がある場合 (多相性を利用することを想定する場合) を除いては関数として定義したほうが良いことも多い。
2024/11/26(火) 12:22:11.23ID:qH2nLRZc
>>967
まず技術的にはRustは孤児ルール(orphan rule)により他へ影響を与える汚染を防げる仕組みがあるのでコンパイルが通るなら大丈夫
新たなメソッドを増やすには自分で用意したトレイトの中で行うことになるのでその自作トレイトをuseしない限り他への汚染の影響は無し

したがってあとは有用性と可読性の問題かな
例えばジェネリックに処理するためのトレイト境界とその新たなメソッドを用意するのは有用かつ必須でよく行われる
単に自作型に変換したいだけならば新たなトレイトとメソッドを用意せずとも
impl From<既存型> for 自作型 して
let x: 自作型 = 既存型値.into(); など
971デフォルトの名無しさん
垢版 |
2024/11/26(火) 12:32:30.35ID:OrSHBPPk
>>970
ありがとうございます
他のライブラリー影響する気がしたので聞いてみました
972デフォルトの名無しさん
垢版 |
2024/11/26(火) 19:48:39.21ID:/2XIgpnc
Traitのimplが出来るのは型を定義したcrateかtraitを定義したcrateだけだから、他のライブラリには影響しない
メソッドの名前が被っていてもそのtraitをuseしないと使えないし、最悪useすることになってもtraitを指定してメソッドを呼べる
973デフォルトの名無しさん
垢版 |
2024/11/27(水) 16:06:33.32ID:ddkklZcJ
「ツールの使い方覚えるだけ」

まさにそれ
2024/11/29(金) 21:54:35.06ID:/9dKvjaK
こうすれば実行時に確定する値を&'staticにできるね
static HOME: LazyLock<String> = LazyLock::new(|| std::env::var("HOME").unwrap());
let home: &'static str = &*HOME;
2024/11/30(土) 00:45:06.70ID:6Z2K+eju
unsafeとは危険という意味で合ってるが、魔女のようなものを狩る行動を意味しない
信念と行動が合致しない方が得だから合致しない
2024/11/30(土) 18:20:12.51ID:D1SGYlac
所有者をスタック上に置くからライフタイム管理が必要になる
それを避けて&'staticするには3つの方法がRustで提供されている
(1) 所有者を最初から持たない
(2) 所有者をスタックに置かない
(3) 所有者を捨てる
2024/11/30(土) 19:42:09.81ID:g3xetMDU
データをRustの外に置けば、ライフタイム管理から逃れられる
たとえばファイルに書いてしまう
2024/11/30(土) 23:10:39.19ID:D1SGYlac
(1) コンパイル時に値が確定して静的に配置されるものが該当
(2) 実行時に値が確定してstatic変数に遅延配置させるものが該当
(3) 実行時に値が確定してleak()させるものが該当
いずれも&'staticで安全に参照できる
2024/11/30(土) 23:33:27.96ID:6Z2K+eju
C++もスマートポインタがあるからポインタ管理を推進する側の勢力だった
だからC++を使わなくてもCで十分という意見に説得力があった
今では、管理に反対する奴も賛成する奴もどっちもC++に不満を感じている
980デフォルトの名無しさん
垢版 |
2024/12/01(日) 21:53:13.54ID:IuCKzQHf
let や let mut を見たとたん、「だーめだ、こりゃあ。数値計算に使えねえ。fortranの方が余程ましだ。」
と思った。大体、letなんてBasicで出てきそうなワードを「変数束縛」という深刻な概念に結びつけている
時点で作った奴はセンスねえと思うわ。
2024/12/01(日) 22:06:15.87ID:s/x9f/ll
ブラックフライデーで複オジポエムが続いてたかと思えばさらに輪をかけた常識知らずが来たw
982デフォルトの名無しさん
垢版 |
2024/12/01(日) 22:10:53.24ID:IuCKzQHf
そうか? 俺にはお前の額に馬と鹿が見えるが
2024/12/01(日) 22:44:04.77ID:iESkoZBr
>>774
アンロードが起きうるstatic変数は制御下に置くためスレッドローカルに置く
thread_local! {
static VAR: RefCell<Foo> = RefCell::new(Foo::new());
}
ちゃんとdropするためメモリリークは起きないことが確認できる
impl Drop for Foo {
fn drop(&mut self) {
println!("DEBUG: drop Foo");
}
}
2024/12/02(月) 13:25:55.50ID:SvUnxJQd
>>980
大丈夫か?比較対象がfortranやbasicでは歳が知れるぞ。今時の言語知らんのかい?
2024/12/02(月) 13:32:19.67ID:3neKGwU7
変数束縛とかいきってるとこにセンス感じないのは同意
2024/12/02(月) 13:38:57.47ID:5A4jg9rQ
ML 系言語が基礎になってるから用語もそっちで一般的なものが使われてる。
2024/12/02(月) 13:43:46.67ID:3neKGwU7
>>986
ML知ってるならより奇妙に感じるはずだよw
2024/12/02(月) 14:01:48.04ID:SvUnxJQd
lispや初期のMLからletの使い方は変わってないと思うけど何がしたくて何が出来ないと言ってるのか分からん。
2024/12/02(月) 14:48:33.18ID:XKXSk/VC
伝統的には、引数とグローバル変数を区別せず自由変数とする
自由ではない変数は束縛されている
ただし関数がネストするなら、引数は束縛変数とするほうが需要に合致する
2024/12/02(月) 18:48:24.16ID:jQxoP1Z8
free variables/bound variablesのbindingと
name bindingのbindingは無関係ではないけど使われる文脈も意味も違う
letの話は後者

それに昔々のThe Bookではvariable bindingsという用語が使われてたが
わかりにくいという理由でかなり前にvariablesという用語に変更されてる
2024/12/02(月) 18:54:23.80ID:UThkx+wo
>>739
メモリリークとは実行中に使用していないメモリが解放されないことでメモリ使用量が膨らんでいくことだから
実行を終えた時にメモリ解放するか否かはどうでもいい話でそれをメモリリークとは呼ばない

Box::leak()でも実行を終えた時にメモリは解放されないがRustでは普通に使われている
例えばcargo crateでもleakさせまくっているが何ら問題ない

cargo-0.84.0/src/cargo/core/package_id.rs: let inner = Box::leak(Box::new(inner));
cargo-0.84.0/src/cargo/core/source_id.rs: let inner = Box::leak(Box::new(inner));
cargo-0.84.0/src/cargo/util/interning.rs: let s = str.to_string().leak();
2024/12/02(月) 20:05:14.90ID:4EvznkF/
最近勉強始めたけど
::で躓いて脱落しそう
2024/12/02(月) 20:19:44.41ID:GZbY5KmK
ダブルコロンは他の言語C++からPHPまで使われており
Rustでもそれらと同様に名前空間を示すpathの区切り文字として使用されている
https://doc.rust-lang.org/reference/paths.html
2024/12/02(月) 20:22:50.81ID:SvUnxJQd
>>990
えーとletという用語に文句言ってるだけで、プログラムの機能的には問題ないということでいいの?
2024/12/02(月) 20:39:13.67ID:B3Y6W1wC
ら、ら、ラストー🦛
2024/12/02(月) 20:39:36.01ID:B3Y6W1wC
ら、ら、ラストー🦛
2024/12/02(月) 20:39:59.86ID:B3Y6W1wC
ら、ら、ラストー🦛
ら、ら、ラストー🦛
2024/12/02(月) 20:40:22.73ID:B3Y6W1wC
ら、ら、ラストー🦛
ら、ら、ラストー🦛
2024/12/02(月) 20:40:45.44ID:B3Y6W1wC
ら、ら、ラストー🦛
ら、ら、ラストー🦛
ら、ら、ラストー🦛
2024/12/02(月) 20:41:08.42ID:B3Y6W1wC
ら、ら、ラストー🦛
ら、ら、ラストー🦛
ら、ら、ラストー🦛
10011001
垢版 |
Over 1000Thread
このスレッドは1000を超えました。
新しいスレッドを立ててください。
life time: 72日 22時間 22分 31秒
レス数が1000を超えています。これ以上書き込みはできません。
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

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