公式
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/
探検
Rust part13
■ このスレッドは過去ログ倉庫に格納されています
2021/11/07(日) 10:04:59.35ID:pJhT3MIE
2021/11/21(日) 04:34:14.82ID:VYuGYhJz
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));
}
fn ntimes_print<T>(n: T, s: &str)
where T: num::Integer + num::ToPrimitive + Clone
{
num::range(T::zero(), n).for_each(|_| print!("{}", s));
}
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);
}
}
少し例を実用的に変えてみましたがトレイト境界(制約)を最小限で以下のようなコードで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);
}
}
2021/11/21(日) 12:10:20.71ID:qtUeCPjG
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=3702e2291f04ef5e40bd5310079972b1
2021/11/21(日) 15:03:50.15ID:szj4saah
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);
}
}
凄い!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);
}
}
87デフォルトの名無しさん
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
}
}
これだけで動作する
それらトレイト境界などのコードの記述も魔法のように消えて短くなる
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
}
}
これだけで動作する
2021/11/21(日) 20:22:13.92ID:ekMm5ue5
timesなら精々u64::MAX回も繰り返すことなさそうだしTからu64に変換するのではだめなの?
2021/11/21(日) 20:32:22.18ID:VYuGYhJz
2021/11/22(月) 10:01:45.21ID:YMaXH3oe
指定するトレイト境界が減った代わりにAPIが劣化してる
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)
}
}
イテレータ版の方が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)
}
}
2021/11/22(月) 12:13:59.22ID:qBbb57Hy
わざわざ外部crateと独自trait使って
n.times().for_each(f)にするくらいなら
(0..n).for_each(f)で十分
n.times().for_each(f)にするくらいなら
(0..n).for_each(f)で十分
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)) }
}
それでは最初の条件のジェネリックを満たせていない
>>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)) }
}
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")
ちゃんと数値型以外でも動きました
ところが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")
ちゃんと数値型以外でも動きました
2021/11/22(月) 15:04:22.59ID:UzgCqcLK
>>93
>それでは最初の条件のジェネリックを満たせていない
ジェネリックにしたければ(T::zero()..n).for_each(f)と書けばいいだけでしょ
単にRangeを返すだけのメソッドを手間かけて微妙に抽象化しても周りが迷惑するだけだぞ
>それでは最初の条件のジェネリックを満たせていない
ジェネリックにしたければ(T::zero()..n).for_each(f)と書けばいいだけでしょ
単にRangeを返すだけのメソッドを手間かけて微妙に抽象化しても周りが迷惑するだけだぞ
2021/11/22(月) 15:23:28.68ID:EEj8G+es
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)
n..mという表記は使えないが、n.times()なら支障なく実装できるかと
自分なら以下みたいに書くけどね
(T: From<i32> + PartialOrd が前提)
(0..).map(T::from).take_while(move ¦x¦ x<n)
98デフォルトの名無しさん
2021/11/22(月) 19:36:28.33ID:3Rtka3dv なるほどね
2021/11/22(月) 19:55:09.41ID:5egSOJea
100デフォルトの名無しさん
2021/11/22(月) 20:04:43.45ID:VyYbXHRo C++じゃないんだから不毛な型パズルはやめろ
101デフォルトの名無しさん
2021/11/22(月) 20:25:52.53ID:gBMgBg1g C++よりマシ
102デフォルトの名無しさん
2021/11/22(月) 20:56:45.47ID:MJpN6tlo 意味のない例で延々とよくやるわ
103デフォルトの名無しさん
2021/11/22(月) 21:02:15.85ID:FLi/1Joa カスタムな型ならRangeよりイテレータ対応が先
104デフォルトの名無しさん
2021/11/22(月) 21:09:17.05ID:fRCpO7Rh StepがunstableなのはさておきFromLiteralみたいなトレイトがあるとZeroやOneの出番が減ってうれしいのかね
T: FromLiteralの時に整数リテラルがT型の値として解釈されるようになるようなイメージ
T: FromLiteralの時に整数リテラルがT型の値として解釈されるようになるようなイメージ
105デフォルトの名無しさん
2021/11/22(月) 21:58:50.69ID:FLi/1Joa try_into()でできるよ
106デフォルトの名無しさん
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にできてコンパイル時にエラー検出できるとベター
struct Foo;
が FromLiteral を実装しているときに
let n: T = 123;
というコードを書くとコンパイラが
let n = T::from_literal("123");
といったコードに変換してくれるイメージ
from_literalはconst fnにできてコンパイル時にエラー検出できるとベター
107デフォルトの名無しさん
2021/11/22(月) 22:10:11.00ID:fRCpO7Rh >>106
TはFooの間違い
TはFooの間違い
108デフォルトの名無しさん
2021/11/23(火) 07:57:08.78ID:9DtS3af5 ねこ
109デフォルトの名無しさん
2021/11/23(火) 10:28:33.41ID:8Ju98kPx https://github.com/rust-lang/team/pull/671
Coreチームがクソだからやめたった、ってこと?
Coreチームがクソだからやめたった、ってこと?
110デフォルトの名無しさん
2021/11/23(火) 13:56:03.32ID:b1gEfTjX const fnが言いたいだけやろ、だれが=演算子でcopyでもなく、言語上ないことになってるコンストラクタでもなく
そんな特異なトレイトを勝手に呼ぶのが嬉しいねん、なにがバター犬や
そんな特異なトレイトを勝手に呼ぶのが嬉しいねん、なにがバター犬や
111デフォルトの名無しさん
2021/11/23(火) 14:58:36.02ID:s6k3uLQ1112デフォルトの名無しさん
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型でも動いたよ
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型でも動いたよ
113デフォルトの名無しさん
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と高階関数で揉める駄スレにどうこう出来る内容ちゃう
現状だって0b0011u32とか0x80u32とか書いてるのに、型定義が横にあるからそれでコンパイル時に
パース処理したいなんてそんな都合の良い言語ちゃうだろ、Raw stringのr"123"とか、Raw bytesとか
とも違うし、確かにfrom_strが"123"を解釈するけどやるにしても、let x: i32 = "123";が通ってから。
でもコンパイル時とはいえ自動型変換に見えるコードは承認しないと思うし、直行性も下がる
こんな場末の酒場みたいな所で言ってもコミッターどころかforと高階関数で揉める駄スレにどうこう出来る内容ちゃう
114デフォルトの名無しさん
2021/11/23(火) 20:58:16.83ID:Oek7vlRG115デフォルトの名無しさん
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して使いますよね
つまり生の数値だけを対象にしていては視点が狭いと思うのです
でも現実のプログラミングでは数値を生で使うよりも
struct Counter { usize } とか
struct Age { usize } とか
struct XxxLength { usize } とかにして
型が異なることをはっきりさせて安全に使いますよね
そして付加情報があればstructのフィールドが複数になることもあったり
あるいはstruct std::time::Durationのようにnanoからsecまで扱えるようにしてもAddをimplして使いますよね
つまり生の数値だけを対象にしていては視点が狭いと思うのです
116デフォルトの名無しさん
2021/11/23(火) 22:15:57.50ID:qrGqDm2c >>115の{ }は( )の誤記ですw
117デフォルトの名無しさん
2021/11/24(水) 03:12:15.58ID:P1gN11rG Stepがstable入りしたら要らなくなる話になにとんでもない破壊的変更を持ち出しているんだ
118デフォルトの名無しさん
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
Length型をn.times().for_each()
Duration型をn.times().for_each()
ジェネリックw
119デフォルトの名無しさん
2021/11/24(水) 05:02:23.28ID:e1u6MioL120デフォルトの名無しさん
2021/11/24(水) 15:22:53.32ID:zkfKZqQ7121デフォルトの名無しさん
2021/11/24(水) 17:05:44.23ID:5wn/1hS5 >>117
コンパイラや標準ライブラリの変更で型推論の結果が変わることは破壊的変更扱いされなかったっけ
コンパイラや標準ライブラリの変更で型推論の結果が変わることは破壊的変更扱いされなかったっけ
122デフォルトの名無しさん
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する感じですかね
なんとなく分かりましたがいきなりコンパイラが自動変換の前に現状で
例えばまずは整数型を例に絞ってやるとして
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する感じですかね
123デフォルトの名無しさん
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を書かなくても済むように出来そう
実際に使ってみる具体例として面倒なので>>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を書かなくても済むように出来そう
124デフォルトの名無しさん
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)]
そして当然ながら動きました
念のため実際に使う時にどうなるかと使えるかを確認すると
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)]
そして当然ながら動きました
125デフォルトの名無しさん
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型についても動きました
あとは>>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型についても動きました
126デフォルトの名無しさん
2021/11/24(水) 18:18:05.49ID:AgL0hXz4 誰も見てねーから別のところでやれ
127デフォルトの名無しさん
2021/11/24(水) 19:13:18.31ID:5wn/1hS5 話題がないんだもん
なんか話題を提供してくれ
なんか話題を提供してくれ
128デフォルトの名無しさん
2021/11/24(水) 23:19:00.01ID:e1u6MioL 結局Derefみたいにコンパイラが自動的に適用して変換してくれればそのintoやfromをプログラムには書かなくて済むんやろ
129デフォルトの名無しさん
2021/11/25(木) 23:08:27.91ID:QVGqalzl ファイルを開く操作って普通に考えたらFile::open_ほにゃらら()みたいなメソッドにOpenOptionsを渡すほうが自然だと思うんですが
OpenOptions::open()みたいな方法を取ってるのってどういう理由からなんでしょうか?
OpenOptions::open()みたいな方法を取ってるのってどういう理由からなんでしょうか?
130デフォルトの名無しさん
2021/11/25(木) 23:59:01.72ID:88pS2ZzI131デフォルトの名無しさん
2021/11/26(金) 00:22:31.18ID:aH1+xhzE >>129
Rustは関数定義でデフォルト値のあるオプション引数をサポートしてないから
オプション引数的な使い方をしたい場合はビルダーパターンを使うのが一般的
File::options().read(true).create(true).open("foo.txt”);みたいな使い方になる
Rustは関数定義でデフォルト値のあるオプション引数をサポートしてないから
オプション引数的な使い方をしたい場合はビルダーパターンを使うのが一般的
File::options().read(true).create(true).open("foo.txt”);みたいな使い方になる
132デフォルトの名無しさん
2021/11/26(金) 09:37:38.31ID:kuMbCEJE うーん
ダサいな
もっときれいにならんの?
ダサいな
もっときれいにならんの?
133デフォルトの名無しさん
2021/11/26(金) 09:50:01.95ID:kuMbCEJE メソッドチェーンって過去の遺物だよね?
バグの温床だし
長いとどこかで消し忘れや二重指定が出て本人が気が付かなくなる
長くなっただけで破綻するんだからおかしい
バグの温床だし
長いとどこかで消し忘れや二重指定が出て本人が気が付かなくなる
長くなっただけで破綻するんだからおかしい
134デフォルトの名無しさん
2021/11/26(金) 10:00:30.74ID:5+U4u14D135デフォルトの名無しさん
2021/11/26(金) 10:06:22.27ID:yaO+xNFa パイプライン演算子大好きとかLisp方面から来た人とかなのかも……
136デフォルトの名無しさん
2021/11/26(金) 10:12:22.08ID:kuMbCEJE え?メソッドチェーンってjqueryが流行ってたころの名残でしょ?
10年ぐらい前
メソッドチェーンなんて書いててだるいだけ
10年ぐらい前
メソッドチェーンなんて書いててだるいだけ
137デフォルトの名無しさん
2021/11/26(金) 10:21:37.95ID:5+U4u14D >>136
JavaScriptも今は関数型プログラミングが主流へと変わりメソッドチェーンだし外部ライブラリを使うインタフェースもメソッドチェーンがよく使われる
そしてRustも同様
どこの古い世界から来たお客さんですか?
JavaScriptも今は関数型プログラミングが主流へと変わりメソッドチェーンだし外部ライブラリを使うインタフェースもメソッドチェーンがよく使われる
そしてRustも同様
どこの古い世界から来たお客さんですか?
138デフォルトの名無しさん
2021/11/26(金) 10:34:43.95ID:E7I1X7f8 メソッドチェーンって関数型由来ではないし
139デフォルトの名無しさん
2021/11/26(金) 11:18:59.37ID:/IsoxS9R140デフォルトの名無しさん
2021/11/26(金) 11:23:55.78ID:/IsoxS9R141デフォルトの名無しさん
2021/11/26(金) 11:31:53.80ID:oSCWFWAt >>140
はえ〜、そうか勉強になったわ
はえ〜、そうか勉強になったわ
142デフォルトの名無しさん
2021/11/26(金) 11:44:41.28ID:kuMbCEJE >>139
二重指定は一方でtrue一方でfalse指定しているパターン
二重指定は一方でtrue一方でfalse指定しているパターン
143デフォルトの名無しさん
2021/11/26(金) 12:05:35.16ID:SqSfLhr2144デフォルトの名無しさん
2021/11/26(金) 12:25:05.02ID:kuMbCEJE 通常のCのオープン関数のほうが100倍キレイで簡潔で合理的だと思うが個人差はあるんだろうな
File::options().read(true).create(true).open("foo.txt”);
これを書くときにリードがtrueだな、createもtrueだな、そしてファイル名はfoo.txtだと言う思考順序で
コード書くとは思えないんですよ常識的に
File::options().read(true).create(true).open("foo.txt”);
これを書くときにリードがtrueだな、createもtrueだな、そしてファイル名はfoo.txtだと言う思考順序で
コード書くとは思えないんですよ常識的に
145デフォルトの名無しさん
2021/11/26(金) 12:29:19.27ID:kuMbCEJE これが美しいと言う人はそれこそ逆ポーランド次元から来た異次元人だと思うよ
146デフォルトの名無しさん
2021/11/26(金) 12:40:54.22ID:R0yJ4Kup なかなか極端な例を出してきたな……
147デフォルトの名無しさん
2021/11/26(金) 12:43:09.59ID:GoGODfBQ148デフォルトの名無しさん
2021/11/26(金) 12:51:53.22ID:kuMbCEJE 逆ポーランド人現る
149デフォルトの名無しさん
2021/11/26(金) 12:53:26.61ID:kuMbCEJE ファイルを開こうと思うときにoptions型から思考がスタートする人は天才なんだろうな
それか飼いならされた人
それか飼いならされた人
150デフォルトの名無しさん
2021/11/26(金) 12:57:20.12ID:kuMbCEJE 言語否定じゃなくてライブラリ設計がおかしい
実用無視の人が設計するとこうなる
実用無視の人が設計するとこうなる
151デフォルトの名無しさん
2021/11/26(金) 12:58:29.05ID:Q6WyUjPa File::open_with_options("foo.txt", &OpenOptions::new().read(true).create(true));
どっちが良いとか悪いとかじゃないと思うがなあ
どっちが良いとか悪いとかじゃないと思うがなあ
152デフォルトの名無しさん
2021/11/26(金) 13:13:18.47ID:kuMbCEJE 美しくないだろ普通に
153デフォルトの名無しさん
2021/11/26(金) 13:13:45.37ID:HMe+psgI OpenOptionsって名前で明らかに「ファイル開く時のオプションですよ」って名前なのにファイル開く操作まで持ってるから気持ち悪いんだよな
同じモジュールでディレクトリはDirBuilderとかあるんだから普通にFileBuilderとかにすりゃええやんとか思っちゃうけどなんか理由があったんかね
同じモジュールでディレクトリはDirBuilderとかあるんだから普通にFileBuilderとかにすりゃええやんとか思っちゃうけどなんか理由があったんかね
154デフォルトの名無しさん
2021/11/26(金) 13:23:36.09ID:kuMbCEJE 確かに他だったらoptionのインスタンスを作ってopenに食わせる感じだな
それもどうかと思うけど
ほぼ定数みたいなものをわざわざ作って食わせるなんて
それもどうかと思うけど
ほぼ定数みたいなものをわざわざ作って食わせるなんて
155デフォルトの名無しさん
2021/11/26(金) 14:04:50.29ID:TIzT5fn9 慣れない人にとっては分かりにくいAPIにならざるを得ないのは確か
ただ他の言語でオプション引数やオーバーロードが2桁あるのが当たり前になってるようなライブラリを見るとそれぞれ一長一短あるなとは思う
ただ他の言語でオプション引数やオーバーロードが2桁あるのが当たり前になってるようなライブラリを見るとそれぞれ一長一短あるなとは思う
156デフォルトの名無しさん
2021/11/26(金) 14:15:29.08ID:Q6WyUjPa >>154
associated constくらい用意してもらってもいいかもね
associated constくらい用意してもらってもいいかもね
157デフォルトの名無しさん
2021/11/26(金) 14:20:28.16ID:Ye0bskEh158デフォルトの名無しさん
2021/11/26(金) 14:57:24.65ID:AxmLr4ZJ > 通常のCのオープン関数のほうが100倍キレイで簡潔で合理的
さっぱりわからんけどw
別に
File::options().readwrite().newfile().open("foo.txt”);
がいいとも悪いとも思わんし
cのopenがいいとも悪いとも思わん
どんな素晴らしいopen見せてくれるのかと思ったらガッカリした
さっぱりわからんけどw
別に
File::options().readwrite().newfile().open("foo.txt”);
がいいとも悪いとも思わんし
cのopenがいいとも悪いとも思わん
どんな素晴らしいopen見せてくれるのかと思ったらガッカリした
159デフォルトの名無しさん
2021/11/26(金) 15:03:20.08ID:BGloBCeB OpenOptionsが分かりにくいってのはそのとおりだと思うし、実際みんなそう思ってるみたいで
ちょうどFile::optionsにするRFCが通るところだよ
ちょうどFile::optionsにするRFCが通るところだよ
160デフォルトの名無しさん
2021/11/26(金) 16:18:02.52ID:Ye0bskEh >>159
stabilizeのPRが10日前に取り込まれたから1月にはリリースされそう
stabilizeのPRが10日前に取り込まれたから1月にはリリースされそう
161デフォルトの名無しさん
2021/11/26(金) 18:16:06.66ID:kuMbCEJE162デフォルトの名無しさん
2021/11/26(金) 19:18:40.42ID:wVYXipKz >>161
それはfopenの仕様(引数の意味とか)を知っているのが前提だからなぁ。
filenameとmodeの順番を間違えたら読み間違える。
メソッドチェーンと比較するなら名前付き引数のメソッド呼び出しじゃない?
あるいはインテリセンス環境下という条件付きか。
それはfopenの仕様(引数の意味とか)を知っているのが前提だからなぁ。
filenameとmodeの順番を間違えたら読み間違える。
メソッドチェーンと比較するなら名前付き引数のメソッド呼び出しじゃない?
あるいはインテリセンス環境下という条件付きか。
163デフォルトの名無しさん
2021/11/26(金) 19:21:46.75ID:Hq7eoo6P >>161
ほんそれ
ほんそれ
164デフォルトの名無しさん
2021/11/26(金) 19:26:21.35ID:kuMbCEJE 仮想のコードで例が適切かどうかわからないけど
File::options().readwrite().newfile().read().open("foo.txt”)
と書いて直後で書き込めねえええええよと叫ぶよりfopenの方がいいだろ;
File::options().readwrite().newfile().read().open("foo.txt”)
と書いて直後で書き込めねえええええよと叫ぶよりfopenの方がいいだろ;
165デフォルトの名無しさん
2021/11/26(金) 19:37:54.04ID:kuMbCEJE あ、ミスった
それはさておき例のメソッドチェーン見ても瞬時に不安しかよぎらない
readwrite() が中で read(true).write(true) してるとして
readonly() が中でread(true)しかしてないんじゃないかとか不安
それはさておき例のメソッドチェーン見ても瞬時に不安しかよぎらない
readwrite() が中で read(true).write(true) してるとして
readonly() が中でread(true)しかしてないんじゃないかとか不安
166デフォルトの名無しさん
2021/11/26(金) 19:47:03.96ID:AxmLr4ZJ167デフォルトの名無しさん
2021/11/26(金) 20:09:04.42ID:XtGzaRsE168デフォルトの名無しさん
2021/11/26(金) 20:37:35.34ID:kuMbCEJE169デフォルトの名無しさん
2021/11/26(金) 20:42:02.78ID:kuMbCEJE cのfopenはメソッドチェーンより簡潔だ
本当は他の言語のenumでいいんだけど
Open("rust.txt",FileMode.Open, FileAccess.Read)
これでバグは出ない
本当は他の言語のenumでいいんだけど
Open("rust.txt",FileMode.Open, FileAccess.Read)
これでバグは出ない
170デフォルトの名無しさん
2021/11/26(金) 20:55:25.49ID:R0yJ4Kup そんなに変わらへんやん、むしろuseで引き込む名前が増えて美しくないやん
171デフォルトの名無しさん
2021/11/26(金) 21:02:27.39ID:Ye0bskEh foo(true, false, true, false) や foo(None, None, None, Some(true)) みたいな呼び出しよりは100倍マシ
172デフォルトの名無しさん
2021/11/26(金) 22:47:08.22ID:r6ugNRE0 ところでreadwrite()とかnewfile()ってなんですか?
173デフォルトの名無しさん
2021/11/27(土) 00:09:21.90ID:riEP2Tv6 OpenOptionsの名称問題はともかく
なぜメソッドをチェーンさせているかというと理由は明白で
OpenOptionsExtトレイトをuseすると使えメソッドが拡張されて.mode()などが使えるようになるからだよ
なぜメソッドをチェーンさせているかというと理由は明白で
OpenOptionsExtトレイトをuseすると使えメソッドが拡張されて.mode()などが使えるようになるからだよ
174デフォルトの名無しさん
2021/11/27(土) 00:15:29.99ID:4eTYjVC9 パイプ演算子は |> いつ実装されるの?
175デフォルトの名無しさん
2021/11/27(土) 00:19:05.68ID:L+2AsAAt どうせ上のtimes()トレイト君でしょ
176デフォルトの名無しさん
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が参画しているということはありうるわけで
それとも歓迎?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が参画しているということはありうるわけで
177デフォルトの名無しさん
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では詰む
元がこうだもんな
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
そしてunix以外にも対応するために
std::os::unix::fs::OpenOptionsExtへ分けたのだろう
このメソッドチェーンビルダー方式以外のAPIでは詰む
178デフォルトの名無しさん
2021/11/27(土) 05:50:15.37ID:IOkCeWcH179デフォルトの名無しさん
2021/11/27(土) 09:55:26.18ID:sBo289Q7 >>174
rustは第一引数がselfの場合にメソッドのレシーバーになるのだから、実質パイプライン
rustは第一引数がselfの場合にメソッドのレシーバーになるのだから、実質パイプライン
180デフォルトの名無しさん
2021/11/27(土) 11:01:40.71ID:kX7QbhiL それはElixirと同じ「なんちゃってパイプライン」でメソッドチェーンが実現できるというだけでは。
ここで欲しいと言われているのは大元のF#のように自由関数やその部分適用が使えるパイプラインのことだろう。
ここで欲しいと言われているのは大元のF#のように自由関数やその部分適用が使えるパイプラインのことだろう。
■ このスレッドは過去ログ倉庫に格納されています
ニュース
- 首相官邸前で「戦争あおるな」 台湾有事巡る答弁に抗議 [蚤の市★]
- 高市首相告白「『なめられない服』を選ぶことに数時間を費やしました」「外交交渉でマウント取れる服、買わなくてはいかんかもなぁ」 [ぐれ★]
- 【高市リスク】立民・小西洋之参院議員「高市総理がとんでもない安全保障オンチで外交オンチ」 [ぐれ★]
- 『DOWNTOWN+』会員数50万人突破で見えてきた 松本人志の“月収4ケタ万円”驚愕収入 [阿弥陀ヶ峰★]
- 【赤坂ライブハウス刺傷】逃走していた自衛官の男(43)を殺人未遂の疑いで逮捕 警視庁 被害女性とは知人関係 [Ailuropoda melanoleuca★]
- 【芸能】永遠の童顔′ウ「光GENJI」53歳になった山本淳一の近影に「若いな?」「元気パワーもらえるよっ」 [湛然★]
- 日本人「憲法9条があれば侵略されないって叫んでた売国左翼のゴミどもは今どんな気分?😂wwwwww」 [441660812]
- 【悲報】東京都民さん、20過ぎてるのに自転車に乗っててて大炎上wwwwwwwwwwww女「いい歳した男で自転車に乗るのは知的障がい者だけだよ? [483447288]
- 広島焼きって食いにくくね
- 【悲報】細田守最新作、超絶爆死しそう
- 【悲報】ミスター東大さん、高度な『ずらし』を披露するも愚民には理解されず大炎上wwwwwwwwwwww [455031798]
- 関西帰りたいから関電か大阪ガスに転職したいんだが?
