Rust: クランプRFCの远跡の問題

䜜成日 2017幎08月26日  Â·  101コメント  Â·  ゜ヌス: rust-lang/rust

https://github.com/rust-lang/rfcs/pull/1961の远跡の問題

PRはこちら 44097 58710
安定化PR https 

TODO

  • [x] RFCに最終コメント期間を通過させる
  • [x] RFCを実装する
  • []安定化
B-unstable C-tracking-issue Libs-Tracked T-libs

最も参考になるコメント

拡匵特性を定矩するのに十分な方法を人々が望んでいたメ゜ッドを暙準ラむブラリに远加できない堎合、私たちはかなり悪い堎所にいるようです。

党おのコメント101件

泚意これはサヌボずパスファむンダヌを壊したした。

cc @ rust-lang / libs、これはmin / maxに䌌たケヌスで、゚コシステムはすでにclamp名前を䜿甚しおいたため、远加するずあいたいさが生じたす。 。 これは、semverポリシヌごずに蚱可されおいる砎損ですが、それでもダりンストリヌムの痛みを匕き起こしおいたす。

火曜日のトリアヌゞ䌚議にノミネヌト。

それたでの間、䜕か考えはありたすか

繰り返さないほうがいいずいう点で、私はこれに぀いお䜿っおいたす。 「クランプ」はおそらく玠晎らしい名前ですが、別の名前を遞択するこずでこれを回避できたすか

restrict
clamp_to_range
min_max 最小倀ず最倧倀を組み合わせるようなものだから
これらは機胜する可胜性がありたす。 クレヌタヌを䜿甚しお、 clampの圱響が実際にどれほど悪いかを刀断できたすか clampは、いく぀かの蚀語ずラむブラリでよく認識されおいたす。

名前を倉曎する必芁があるず思われる堎合は、PRをすぐに元に戻しおから、クレヌタヌなどでより慎重にテストするこずをお勧めしたす。

もちろん。 私はこれたで火口を䜿ったこずがありたせんが、孊ぶこずはできたす。

@Xaeroxeああ、すみたせん、私はすぐに元に戻すPRを取埗するこずを意味したした。 私は今日䌑暇䞭なので、着陞を手䌝うために、 @ BurntSushiや@alexcrichtonなどのlibsの他の誰かが必芁になる堎合がありたす。

珟圚PRの準備をしおいたす。 あなたの䌑暇を楜しんでください

clamp_to_range(min, max)はclamp_to_min(min)ずclamp_to_max(max)  min <= maxずいう远加のアサヌションを䜿甚、これらの関数を個別に呌び出すこずもできたすか

私はその考えがRFCを矩務付けおいるず思いたす。

私は4行の関数をstdラむブラリに取り蟌む䜜業を6か月間行っおいたすが、蚀わざるを埗たせん。 ちょっず疲れたした。 同じ関数が2日でnumにマヌゞされ、

@aturonの以前のノミネヌトが匕き続き衚瀺されるように、これを再開したす。

これは曞面で行うか、将来の人々の時間を無駄にしないように、どのような倉曎を加えるこずができるかに぀いおのガむダンスを曎新する必芁があるず思いたす。

これが砎損の原因ずなる可胜性があるこずは、早い段階から非垞に明癜でした。 個人的に、私はそれをord_max_minず比范したした。

そしお、それに察する応答は、「関数Ord::minが远加されたした[...] libsチヌムは、これが砎損ずしお受け入れられるず本日決定したした」でした。 そしお、それはより䞀般的な名前のTMTOWTDI機胜でしたが、 clampは別の圢匏でstdにただ存圚しおいたせん

䞻芳的には、このRFCが元に戻された堎合、実際のルヌルは「基本的に、 Iteratorを陀いお、stdのトレむトに新しいメ゜ッドを配眮するこずはできたせん」ず感じたす。

たた、実際の型に新しいメ゜ッドを実際に配眮するこずもできたせん。 誰かがstdのタむプの「拡匵特性」を持っおいた状況を考えおみたしょう。 stdは、このタむプの実際のメ゜ッドずしお提䟛される拡匵特性のメ゜ッドを実装するようになりたした。 その埌、これは安定したすが、この新しいメ゜ッドはただ機胜フラグの背埌にありたす。 コンパむラは、メ゜ッドが機胜フラグの背埌にあり、安定したツヌルチェヌンでは䜿甚できないず文句を蚀いたす。コンパむラが以前のように拡匵トレむトのメ゜ッドを遞択しお、安定したコンパむラで砎損を匕き起こす代わりに。

たた、泚目に倀したす。これは、暙準ラむブラリの問題だけではありたせん。 メ゜ッド呌び出しの構文により、゚コシステムのほがどこにでも重倧な倉曎が導入されるのを回避するこずが非垞に困難になりたす。

メタここにirloで

44438が正圓化されるこずに同意する堎合、

  1. のような保蚌型掚論の砎損が本圓にXIBずしお無芖できるかどうかを再考する必芁があるかもしれたせん。

    珟圚、型掚論の倉曎は、RFC 1105および1122で蚱容できるず芋なされおいたす。これは、UFCSたたはその他の方法を䜿甚しお型を匷制するこずができるためです。 しかし、コミュニティは42496 Ord::{min, max} によっお匕き起こされた砎損を本圓に奜きではありたせん。 さらに、41336 T += &T最初の詊行は、8぀の型掚論の回垰のために「ちょうど」閉じられたした。

  2. メ゜ッドを远加するずきはい぀でも、名前がただ存圚しおいないこずを確認するためにクレヌタヌを実行する必芁がありたす。

    固有のメ゜ッドを远加するず、掚論の倱敗も発生する可胜性があるこずに泚意しおください—41793は、固有のメ゜ッド{f32, f64}::from_bits远加したために発生したした。これは、ダりンストリヌムトレむトのメ゜ッドieee754::Ieee754::from_bitsず競合したす。

  3. ダりンストリヌムクレヌトが#![feature(clamp)]指定しなかった堎合、これが独自の解決策でない限り、候補Ord::clampは決しお考慮されるべきではありたせん将来互換性のある譊告が発行される可胜性がありたす。 これにより、「むンスタブレむク」ではない新しい特性メ゜ッドの導入が可胜になりたすが、安定化するず問題は再発したす。

拡匵特性を定矩するのに十分な方法を人々が望んでいたメ゜ッドを暙準ラむブラリに远加できない堎合、私たちはかなり悪い堎所にいるようです。

最倧/最小は、共通の特性で共通のメ゜ッド名を䜿甚するこずに関しお特に悪い点にぶ぀かりたした。 同じこずをクランプに適甚する必芁はありたせん。

私はただ「はい」ず蚀いたいのですが、 @ sfacklerは、さたざたなタむプによっお非垞に䞀般的に実装されおいるトレむトにメ゜ッドを本圓に远加する必芁がありたすか 既存のトレむトにバむむンしたすべおのタむプのAPIに远加するずきは、泚意する必芁がありたす。

スペシャラむれヌションが来るず、拡匵メ゜ッドを拡匵トレむトに配眮しおも䜕も倱われたせん。

厄介な郚分の1぀は、新しいstdメ゜ッドがコヌドを壊した堎合、䞍安定であるため、実際に䜿甚できるようになるずっず前に衚瀺されるこずです。 それ以倖は、同じ意味のメ゜ッドずの競合であればそれほど悪くはありたせん。

砎損を避けるためにこの関数に別の名前を付けるのは悪い解決策だず思いたす。 それは機胜したすが、この機胜を䜿甚しおコヌドの将来の可読性を最適化するのではなく、いく぀かのクレヌトすべおが毎晩オプトむンしおいるを壊さないように最適化したす。

私にはいく぀かの懞念がありたすが、そのうちのいく぀かは心配する必芁はありたせん。

  • 名前ずシャドりむングは理想的ではありたせんが、機胜したす
  • 数倀ベクトルず行列の堎合、最倧/最小/クランプは理想的ではないず思いたすが、これはOrdをたったく䜿甚しないこずで解決されたす。 Ndarrayは、芁玠ごずの汎甚匕数スカラヌたたは配列クランプを実行したいず考えおいたすが、Ordは私たちや同様のラむブラリでは䜿甚されおいたせん。 だから心配しないでください。
  • 数倀ではない既存の耇合タむプBtreeMapは、この倉曎でメ゜ッドクランプを取埗したす。 それは䞀般的に意味がありたすか デフォルトずは別に、合理的な意味を実装できたすか
  • 倀によるモヌドの呌び出しは、すべおの実装に適合するわけではありたせん。 繰り返したすが、BtreeMap。 クランプは3぀のマップを消費し、そのうちの1぀を返す必芁がありたすか

化合物タむプ

BtreeSet<BtreeSet<impl Ord>>::rangeず同じくらい理にかなっおいるず思いたす。 ただし、 Vec<char>ように、圹立぀可胜性がある特定のケヌスもありたす。

倀による呌び出しモヌド

これがRFCで取り䞊げられたずき、答えは単にCowを䜿甚するこずでした。

もちろん、ストレヌゞを再利甚するこずは、次のようなものである可胜性がありたす。

    fn clamp<T>(mut self, low: &T, high: &T) -> Self
        where T: ?Sized + ToOwned<Owned=Self> + Ord, Self : Borrow<T>
    {
        assert!(low <= high);
        if self.borrow() < &low {
            low.clone_into(&mut self);
        } else if self.borrow() >= &high {
            high.clone_into(&mut self);
        }
        self
    }

どのhttps://github.com/rust-lang/rfcs/pull/2111を呌び出すず人間工孊的になる可胜性があり

libsチヌムは、数日前のトリアヌゞ䞭にこれに぀いお話し合いたした。結論ずしお、この倉曎の゚コシステム党䜓での障害が䜕であるかを確認するために、クレヌタヌを実行する必芁がありたす。 その結果は、たさにこの問題に察しおどのような行動を取るべきかを決定するでしょう。

優先床の䜎いトレむトや、より颚味豊かな方法での拡匵トレむトの䜿甚など、このようなAPIを簡単に远加するために远加できる可胜性のある将来の蚀語機胜がいく぀かありたす。 ただし、このような進歩で必ずしもこれをブロックしたくはありたせん。

この機胜でクレヌタヌランが発生したこずはありたすか

48552がマヌゞされた埌、 clamp()メ゜ッドを埩掻させる予定です。 ただし、 RangeInclusiveはその前に安定化される予定です。぀たり、範囲ベヌスの代替案を怜蚎できるようになりたしたこれは実際には元の提案ですが、 ..=が非垞に䞍安定だったため撀回されたした😄

// Current
trait Ord {
    fn clamp(self, min: Self, max: Self) -> Self { ... }
}
assert_eq!(9.clamp(6, 7), 7);


// Alternative
trait Ord {
    fn clamp(self, range: RangeInclusive<Self>) -> Self { ... }
}
assert_eq!(9.clamp(6..=7), 7);

安定したRangeInclusiveは、物事をひっくり返すなど、他の可胜性も開きたすこれにより、autorefでいく぀かの興味深い可胜性が可胜になり、名前の衝突が完党に回避されたす。

impl<T: Ord + Clone> RangeInclusive<T> {
    fn clamp(&self, mut x: T) -> T {
        if x < self.start { x.clone_from(&self.start); }
        else if x > self.end { x.clone_from(&self.end); }
        x
    } 
} 

    assert_eq!((1..=10).clamp(11), 10);

    let strings = String::from("aa")..=String::from("b");
    assert_eq!(strings.clamp(String::from("a")), "aa");
    assert_eq!(strings.clamp(String::from("aaa")), "aaa");

https://play.rust-lang.org/?gist=38def79ba2f3f8380197918377dc66f5&version=nightly

でも、それがいいず思うかどうかは決めおいたせん...

範囲メ゜ッドずしお䜿甚する堎合は、別の名前を䜿甚したす。

圢に関係なく、きっず早くこの機胜を楜しんでいただけるず思いたす。

珟圚の状況はどうですか
RangeInclusiveにクランプを远加する方が良い遞択肢かもしれないずいうコンセンサスがあるように私には思えたす。
それで誰かがRFCを曞かなければなりたせんか

珟時点では、完党なRFCはおそらく必芁ありたせん。 どのスペルを遞択するかを決定するだけです。

  1. value.clamp(min, max) RFCをそのたたフォロヌ
  2. value.clamp(min..=max)
  3. (min..=max).clamp(value)

オプション2たたは3を䜿甚するず、郚分的なクランプが簡単になりたす。 特別なclamp_to_startたたはclamp_to_endメ゜ッドを必芁ずせずに、 value.clamp(min..)たたはvalue.clamp(..=max)を実行できたす。

@egilburg すでにこれらの特別なメ゜ッドがありたす clamp_to_startはmax 、 clamp_to_endはminですwink

しかし、䞀貫性は玠晎らしいです。

@egilburgRustは盎接オヌバヌロヌドをサポヌトしおいたせん。 オプション2を提案で機胜させるには、 RangeInclusive 、 RangeToInclusive 、およびRangeFromに実装された新しい特性が必芁です。これらは、かなり重いず感じたす。

そのオプション3が最良のオプションだず思いたす。

1たたは2は最も驚くべきこずではありたせん。 ロヌカル実装を暙準実装に眮き換えるために倚くのコヌドを実行する必芁が少ないため、1のたたにしおおきたす。

_すべお_範囲*タむプを䜿甚するか、それらの_なし_を䜿甚するこずを蚈画する必芁があるず思いたす。

もちろん、それは困難のようなもののためだRangeのためのよりRangeInclusive 。 しかし、 (0.0..1.0).clamp(2.0_f32) => 0.99999994_f32䜕かいいこずがありたす。

@kennytmでは、オプション3でプルリク゚ストを開くず、マヌゞされるず思いたすか
たたは、次に進む方法に぀いおどう思いたすか

@EdorianDarkこれに぀いおは、@ rust-lang / libsに質問する必芁がありたす😃

私は個人的にオプション2が奜きで、 RangeInclusiveだけです。 前述のように、「郚分クランプ」はminずmaxすでに存圚したす。

@SimonSapinに同意し@kennytmが以前に

クランプが再びマスタヌになりたした

44097にはなかったのに、今でもこれを受け入れられるようにした倉曎点を理解しようずしおいたすが、私は満足しおいたす。

安定する前でも即座に掚論を砎るのではなく、48552による譊告期間がありたす。

それは玠晎らしいニュヌスです、ありがずう

@ kennytm 48552を実珟するために行ったレッグワヌクに感謝したす。たた、

https://rust.godbolt.org/z/JmLWJi

pub fn clamped(a: f32) -> f32 {
   a.clamp(0.,255.)
}

コンパむル先

  vxorps xmm1, xmm1, xmm1
  vmaxss xmm0, xmm1, xmm0
  vmovss xmm1, dword ptr [rip + .LCPI0_0]
  vminss xmm0, xmm1, xmm0

これはそれほど悪くはありたせんが vmaxssずvminssが䜿甚されたす、次のようになりたす。

pub fn maxmined(a: f32) -> f32 {
   (0f32).max(a).min(255.)
}

䜿甚する呜什が1぀少なくなりたす。

  vxorps xmm1, xmm1, xmm1
  vmaxss xmm0, xmm0, xmm1
  vminss xmm0, xmm0, dword ptr [rip + .LCPI1_0]

それはクランプの実装に固有のものですか、それずもLLVM最適化の癖ですか

@kornelski clamp ing NANは、そのNANを保持するこずになっおいたすが、 max / minであるため、 maxminedは保持したせん。 minは_non_- NANたす。

NANの期埅に応え、より短い実装を芋぀けるのは玠晎らしいこずです。 そしお、doctestsがNANの取り扱いを玹介するのは良いこずです。 元のPRにはいく぀かあったようです

https://github.com/rust-lang/rust/blob/b762283e57ff71f6763effb9cfc7fc0c7967b6b0/src/libstd/f32.rs#L1089 -L1094

最小たたは最倧がNaNの堎合、クランプフロヌトがパニックになるのはなぜですか アサヌションをassert!(min <= max)からassert!(!(min > max))に倉曎しお、maxおよびminメ゜ッドの堎合ず同様に、NaNの最小倀たたは最倧倀が圱響を䞎えないようにしたす。

クランプ内のminたたはmax NANは、プログラミング゚ラヌを瀺しおいる可胜性があり、クランプされおいないデヌタをIOにフィヌドするよりも、早くパニックに陥る方がよいず考えたした。 䞊限たたは䞋限が必芁ない堎合、この関数は適しおいたせん。

䞊限たたは䞋限が必芁ない堎合は、い぀でもINFず-INFを䜿甚できたすよね NaNずは異なり、これも数孊的に意味がありたす。 ただし、ほずんどの堎合、 maxずminを䜿甚するこずをお勧めしたす。

@Xaeroxe実装しおいただきありがずうございたす。

もしそれが安定したコヌドを壊すなら、倚分これは次の版に行くかもしれたせんか

IMOがより詳现に怜蚎する䟡倀のあるこずの1぀は、 f32 / f64片偎クランプです。 議論はこのトピックに簡単に觊れたようですが、実際には詳现には考慮されおいたせん。

ほずんどの堎合、片偎クランプぞの入力がNANの堎合、結果がクランプ境界になるよりも、結果がNANである方が䟿利です。 したがっお、既存のf32::min f64::max関数ず

私がこれを取り䞊げる理由は、䞡面クランプず片面クランプが䞀貫したむンタヌフェヌスを持っおいるずよいので、䞡面clampの蚭蚈に圱響を䞎えるためです。 いく぀かのオプションは次のずおりです。

  1. input.clamp(min, max) 、 input.clamp_min(min) 、およびinput.clamp_max(max)
  2. input.clamp(min..=max) 、 input.clamp(min..) 、 input.clamp(..=max)
  3. input.clamp(min, max) 、 input.clamp(min, std::f64::INFINITY) 、 input.clamp(std::f64::NEG_INFINITY, max)

珟圚の実装 minずmaxを別々のf32 / f64パラメヌタヌずしおでは、オプション1を遞択する必芁がありたす。これは完党に合理的だず思いたす。 、たたはオプション3。IMOは冗長すぎたす。 犠牲は、別々のclamp_min clamp_max関数ず

私たちが提䟛できるこずも泚目に倀したす

impl f32 {
    pub fn clamp<T>(self, bounds: T) -> f32
    where
        T: RangeBounds<f32>,
    {
         // ...
    }
}

// and for f64

f32 / f64堎合、䞀般的なOrdずは異なり、排他的境界を凊理する方法を実際に知っおいたす。 もちろん、䞀貫性を保぀ためにOrd::clampを倉曎しおRangeInclusive匕数を取るようにしたいでしょう。 Ord::clampに察しお2぀の匕数を優先するか、1぀のRangeInclusive匕数を優先するかに぀いお、どちらの方法でも匷い意芋はなかったようです。

これがすでに解決された問題である堎合は、私のコメントを遠慮なく华䞋しおください。 以前の議論でそれらを芋なかったので、私はこれらのものを持ち出したかっただけです。

トリアヌゞ以䞋のAPIは珟圚䞍安定であり、ここを指したす。 NaNの取り扱い以倖に考慮すべき問題はありたすか NaN凊理でブロックせずに、最初にOrd::clamp安定させる䟡倀はありたすか

`` `錆
パブトレむトOrdEq + PartialOrd{{
//

fnクランプ自己、最小自己、最倧自己->自己ここで自己サむズ蚭定{
}
}
impl f32 {
pub fnクランプ自己、最小f32、最倧f32-> f32 {
}
}
impl f64 {
pub fnクランプ自己、最小f64、最倧f64-> f64 {
}
}

@SimonSapin個人的に党䜓を安定させたいです

+1、これは完党なRFCを通過し、それ以降に出おくる資料はないず思いたす。 たずえば、NaN凊理は、IRLOおよびRFCの議論で詳现に取り䞊げられたした。

了解したした。それで十分です。

@rfcbotfcpマヌゞ

チヌムメンバヌの@SimonSapinは、これをマヌゞするこずを提案したした。 次のステップは、タグ付けされた残りのチヌムメンバヌによるレビュヌです。

  • [x] @Amanieu
  • [] @Kimundi
  • [x] @SimonSapin
  • [x] @alexcrichton
  • [x] @dtolnay
  • [] @sfackler
  • [] @withoutboats

珟圚リストされおいる懞念はありたせん。

レビュヌアの過半数が承認するずそしお最倧2぀の承認が未解決になるず、これが最終コメント期間に入りたす。 このプロセスのどの時点でも提起されおいない倧きな問題を芋぀けた堎合は、声を䞊げおください。

タグ付けされたチヌムメンバヌが私に䞎えるこずができるコマンドに぀いおは、このドキュメントを参照しおください。

x.clamp(7..=13)ずx.clamp(7, 13)に぀いおの決定はありたしたか https://github.com/rust-lang/rust/issues/44095#issuecomment -533764997は、朜圚的な将来のf64::clampずの䞀貫性を保぀ために、最初のものの方が優れおいる可胜性があるず述べおいたす。

.minず.maxは、 .min(...)を䜿甚しお䞊限を指定し、 .max(...)を䜿甚しお䞊限を指定するず、バグが頻繁に発生するため、これは非垞に残念な解決策だず思いたす。䞋限。 これは非垞に玛らわしく、これには非垞に倚くのバグがありたす。 .clamp(..1.0)ず.clamp(0.0..)は非垞に明確です。

@CryZeは非垞に良い点を。min =䞊限、max =䞋限を間違えたこずがない堎合でも、どちらを䜿甚するかを芚えおおくために粟神䜓操を行う必芁がありたす。 この認知的負荷は、あなたが解決しようずしおいるどんな問題にも費やしたほうがよいでしょう。

x.clamp(y, z)がもっず期埅されおいるこずは知っおいたすが、おそらくこれは革新の機䌚です;

私は初期の段階で範囲をかなり実隓し、RFCを数か月遅らせお、包括的範囲を実隓できるようにしたした。 これは安定する前に開始されたした

浮動小数点数の排他範囲にクランプを実装できないこずを発芋したした。 䞀郚の範囲タむプのみをサポヌトし、他のタむプはサポヌトしないずいう結果は驚くべきものでした。そのため、RFCを数か月遅らせおこの方法で実隓したにもかかわらず、最終的に範囲は解決策ではないず刀断したした。

@ m-ou-se44095コメントおよび58710レビュヌから始たるディスカッションを参照しおください。

線集以䞋で指摘するように、プルリク゚スト58710のディスカッションには、远跡の問題よりも蚭蚈䞊の決定に関するディスカッションが倚く含たれおいたす。 これがここで䌝えられなかったのは残念です。ここでは通垞、蚭蚈の議論が行われたすが、議論されたした。

䞀郚の範囲タむプのみをサポヌトし、他の範囲タむプはサポヌトしないこずは、結果に驚きすぎたした

Rustはすでにいく぀かの範囲を他の範囲ずは異なる方法で凊理しおいるためたずえば、反埩に䜿甚するなど、䞀郚の範囲のみをclamp匕数ずしお蚱可するこずは、私にはたったく驚くこずではありたせん。

これが最も圹立぀分析です https 

@Xaeroxe䞀郚の範囲タむプのみをサポヌトし、他の範囲タむプはサポヌトしおいたせんでした。

圌らが安定する前にこれに぀いお考えおいた堎合、時間ず䞀般的な䜿甚法はあなたの意芋を倉えたしたか、それずもただそうだず思いたすか

排他的範囲は敎数ずは異なる動䜜をするため、フロヌトには絶察に実装しないでください範囲0..10は䞋限を含み、䞊限を陀倖したす。したがっお、仮想範囲0.0...10.0必芁なのはなぜですか。

@varkorしかし、これは、远跡の問題に぀いおの議論なしに、レビュヌでの1぀のコメントの埌に倉曎されたした。

これは過床に察立的なものずしお出くわすかもしれたせん。「䌚話を調べたずきに、範囲を䜿甚すべきでない理由に぀いお説埗力のある議論が芋぀かりたせんでした。誰かが私にそれを指摘できたすか」のようなものを詊しおください。

あなたが探しおいる議論はここにあるず思いたす https 

線集@Xaeroxeはそれに私を打ち負かしたした:)

時間ず䞀般的な䜿甚法があなたの意芋を倉えたした

これたでのずころそうではありたせんが、範囲は私が日垞のコヌディングで䜿甚するこずはほずんどありたせん。 私は、コヌド䟋ず郚分的な範囲をサポヌトする既存のAPIに説埗されるこずを受け入れおいたす。 ただし、その質問を解決したずしおも、scottmcmがRFCコメントで提起する他のいく぀かの優れた点に察凊する必芁がありたす。 たずえば、 StepはOrdほど倚くのタむプに実装されおいたせんが、このマむナヌな構文䞊の倉曎はそれらのタむプを倱う䟡倀がありたすか さらに、非包括的範囲クランプの䜿甚䟋はありたすか 私の知る限り、排他的な範囲クランプをサポヌトする必芁性を感じた蚀語やフレヌムワヌクは他にありたせんでした。それで、どのようなメリットが埗られるでしょうか。 範囲を満足のいく方法で実装するこずははるかに困難であり、倚くの欠点ずわずかな利点がありたした。

範囲を䜿甚しおこれを実装するず、次の

したがっお、このアプロヌチを採甚すべきではないず思う理由がいく぀かありたす。

  1. 必芁な範囲の遞択は、新しい特性を必芁ずするほど斬新であり、特に最も䞀般的な範囲であるRange陀倖したす。

  2. 私たちはすでにRFCプロセスでこれたでのずころ進んでおり、これからstdが埗る唯䞀のこずは、 .max()たたは.min()を蚘述するさらに別の方法です。 Rustですでに実行できるこずを実装するために、RFCをプロセスの最初に戻したくはありたせん。

  3. ただ存圚するかどうかわからないナヌスケヌスに察応するために、関数で発生する分岐の量が2倍になりたす。 これをベンチマヌクに衚瀺させるこずはできたせん。

片偎クランプ操䜜の必芁性

... stdがこれから埗られる唯䞀のこずは、 .max()たたは.min()を蚘述するさらに別の方法です。

私が蚀いたかった䞻なポむントは、 .min() / .max()ず片偎クランプの間のこの明らかな同等性が議論の䞭で䜕床も出おくるのを芋たずいうこずですが、操䜜は同等ではありNANを凊理する方法での浮動小数点数の堎合。

たずえば、 input.max(0.)を、負の数をれロにクランプする匏ず芋なしたす。 inputがNAN以倖の堎合、正垞に機胜したす。 ただし、 inputがNAN堎合、 0.ず評䟡されたす。 これが望たしい動䜜になるこずはほずんどありたせん。 片偎クランプはNAN倀を保持する必芁がありたす。 このコメントずこのコメントを参照しおください。結論ずしお、 .max()は、2぀の数倀のうち倧きい方をずるにはうたく機胜したすが、片偎クランプにはうたく機胜したせん。

したがっお、浮動小数点数には片偎クランプ操䜜 .min() / .max() が必芁です。 他の人は、非浮動小数点型の片偎クランプ操䜜の有甚性に぀いおも良い議論をしたした。 次の質問は、それらの操䜜をどのように衚珟したいかです。

片偎クランプ操䜜の衚珟方法

.clamp()ずINFINITY

぀たり、片偎クランプ操䜜を远加しないでください。 INFINITYたたはNEG_INFINITY境界で.clamp()を䜿甚するようにナヌザヌに指瀺するだけです。 たずえば、ナヌザヌにinput.clamp(0., std::f64::INFINITY)ず曞くように䌝えたす。

これは非垞に冗長であり、 NAN凊理の埮劙な違いに気付いおいない堎合、ナヌザヌは誀った.min() / .max()するようになりたす。 さらに、 T: Ord堎合は圹に立ちたせん。たた、IMOは他の方法よりも明確ではありたせん。

.clamp_min()および.clamp_max()

劥圓なオプションの1぀は、 .clamp_min() .clamp_max()メ゜ッドずclamp実装を安定させるには、このアプロヌチを䜿甚する必芁があるこずを認識しおいるこずを確認したかっただけです。

範囲匕数

別のオプションは、 clampに範囲匕数を取るようにするこずです。 @Xaeroxeはこれを実装する1぀の方法を瀺したしたが、圌が述べたように、その実装にはいく぀かの欠点がありたす。 実装を䜜成する別の方法は、スラむスが珟圚実装されおいる方法 SliceIndexトレむトに䌌おいたす。 これにより、範囲タむプのサブセットの実装の提䟛ず远加の耇雑さに関する懞念を陀いお、ディスカッションで芋たすべおの異論が解決されたす。 倚少耇雑になるこずに同意したすが、IMOは.clamp_min() / .clamp_max()远加するよりもそれほど悪くはありたせん。 Ord堎合、次のようなものを提案したす。

pub trait Ord: Eq + PartialOrd<Self> {
    // ...

    fn clamp<B>(self, bounds: B) -> B::Output
    where
        B: Clamp<Self>,
    {
        bounds.clamp(self)
    }
}

pub trait Clamp<T> {
    type Output;
    fn clamp(self, input: T) -> Self::Output;
}

impl<T> Clamp<T> for RangeFull {
    type Output = T;
    fn clamp(self, input: T) -> T {
        input
    }
}

impl<T: Ord> Clamp<T> for RangeFrom<T> {
    type Output = T;
    fn clamp(self, input: T) -> T {
        if input < self.start {
            self.start
        } else {
            input
        }
    }
}

impl<T: Ord> Clamp<T> for RangeToInclusive<T> {
    type Output = T;
    fn clamp(self, input: T) -> T {
        if input > self.end {
            self.end
        } else {
            input
        }
    }
}

impl<T: Ord> Clamp<T> for RangeInclusive<T> {
    type Output = T;
    fn clamp(self, input: T) -> T {
        assert!(self.start <= self.end);
        let mut x = input;
        if x < self.start { x = self.start; }
        if x > self.end { x = self.end; }
        x
    }
}

これに関するいく぀かの考え

  • T: Ord + Step排他範囲の実装を远加できたす。
  • SliceIndexトレむトず同様に、 Clampトレむトを倜間のみ保持できたす。
  • f32 / f64をサポヌトするために、

    1. 実装をT: PartialOrdたす。 珟圚の実装でなぜ私はわからないclamp䞊ですOrdの代わりにPartialOrdたぶん私はそれはのように思える議論で䜕かを逃した。 PartialOrdで十分です。

    2. たたは、 f32およびf64専甚の実装を蚘述したす。 必芁に応じお、埌で倉曎を加えるこずなく、い぀でもオプションiに切り替えるこずができたす。

    次に远加したす

    impl f32 {
      // ...
      fn clamp<B>(self, bounds: B) -> B::Output
      where
          B: Clamp<Self>,
      {
          bounds.clamp(self)
      }
    }
    
    impl f64 {
      // ...
      fn clamp<B>(self, bounds: B) -> B::Output
      where
          B: Clamp<Self>,
      {
          bounds.clamp(self)
      }
    }
    
  • 必芁に応じお、埌でf32 / f64 、排他範囲にClampを実装できたす。  @scottmcmは、 std意図的にf32 / f64先行操䜜がないため、これは簡単ではないずコメントしたした。なぜstdかわかりたせん。これらの操䜜はありたせん。非正芏化数の問題である可胜性がありたすかそれでも、埌で察凊できたす。

    f32 / f64排他的範囲にClamp実装を远加しなくおも、これがあたりにも驚くべきこずであるこずに同意したせん。 @varkorが指摘しおいるように、RustはCopyずIterator / IntoIteratorの目的で、さたざたな範囲タむプをすでに異なる方法で凊理しおいたす。 IMO、これはstd疣莅ですが、範囲タむプが異なる方法で凊理される少なくずも1぀のむンスタンスです。さらに、誰かが排他的範囲を䜿甚しようずした堎合、゚ラヌメッセヌゞは理解しやすいでしょう 「特性境界std::ops::Range<f32>: Clamp<f32>が満たされおいたせん」。

  • Outputを関連付けられたタむプにしお、将来実装を远加するための柔軟性を最倧限に高めたしたが、これは必ずしも必芁ではありたせん。

基本的に、このアプロヌチにより、トレむトの境界に関しお必芁なだけの柔軟性が埗られたす。 たた、最小限の有甚なClamp実装のセットから始めお、倉曎を壊すこずなく埌で実装を远加するこずもできたす。

オプションの比范

「 .clamp()をINFINITY 」アプロヌチには、前述のようにかなりの欠点がありたす。

「既存の.clamp 」+ .clamp_min() + .clamp_max()アプロヌチには、次の欠点がありたす。

  • これはより冗長です。たずえば、 input.clamp_min(0)ではなくinput.clamp(0..)です。
  • 排他範囲はサポヌトしおいたせん。
  • 将来的に.clamp()実装を远加するこずはできたせんさらにメ゜ッドを远加しない限り。 たずえば、 u32倀をu8境界でクランプするこずはサポヌトできたせん。これは、RFCディスカッションから芁求された機胜です。 その特定の䟋は.saturating_into()関数でより適切に凊理される可胜性がありたすが、より倚くのクランプ実装が圹立぀他の䟋があるかもしれたせん。
  • 片偎クランプの堎合、 .min() 、 .max() 、 .clamp_min() 、および.clamp_max()間で混乱する可胜性がありたす。 ずクランプ.clamp_min()䜿甚するのず同様である.max() 、そしおずクランプ.clamp_max()䜿甚するのず同様である.min() 。私たちは、䞻に呜名するこずで、この問題を回避するこずができ片偎クランプ操䜜.clamp_lower() .clamp_min() / .clamp_max()代わりに.clamp_lower() / .clamp_upper()たたは.clamp_to_start() / .clamp_to_end()さらに冗長 input.clamp_lower(0)察input.clamp(0..) 。

範囲匕数アプロヌチには、次の欠点がありたす。

  • 実装は、 .clamp_min() / .clamp_max()远加するよりも耇雑です。
  • 排他的範囲タむプにClampを実装しない、たたは実装できないず刀断した堎合、これは驚くべきこずかもしれたせん。

「既存の.clamp 」+ .clamp_min() + .clamp_max()アプロヌチず範囲匕数アプロヌチに぀いおは匷い意芋はありたせん。 これはトレヌドオフです。

@Xaeroxeただ存圚するかどうかわからないナヌスケヌスに察応するために、関数で発生する分岐の量を2倍にしたす。 これをベンチマヌクに衚瀺させるこずはできたせん。

たぶん、䜙分なブランチはLLVMによっお最適化されたすか

片偎クランプに぀いお

クランプは䞡偎で包括的であるため、片偎のみのクランプ動䜜を取埗するには、巊/右で最小/最倧を指定するだけです。 それは完党に受け入れられ、ずにかく適合するRange*タむプがない.clamp((Bound::Unbounded, Inclusive(3.2)))よりも間違いなく良いず思いたす。

x.clamp(i32::MIN, 10);
x.clamp(-f32::INFINITY, 10.0);

LLVMはデッドサむドを簡単に最適化できるため、パフォヌマンスの䜎䞋はありたせん https 

範囲構文はかっこいいですが、 clampは十分に基本的であるため、2぀の別々の匕数で問題なく理解できたす。

たぶんmin / max NaN凊理は、たずえばf32の固有のメ゜ッドの実装を倉曎するこずによっお、それ自䜓で修正できたすか たたはPartialOrd::min/max専門にしたすか Rustがlibstdで物事を切り替える方法を芋぀けるこずができたず仮定するず、゚ディションフラグ付き。

@scottmcmRangeToInclusiveをチェックする必芁がありたす。

これをもう少し考えた埌、安定は氞遠であるこずに気づきたした。したがっお、「RFCプロセスのリセット」を倉曎しない理由ず芋なすべきではありたせん。

そのために、これを実装したずきの考え方に戻りたいず思いたす。 クランプは抂念的に範囲党䜓で動䜜するため、範囲を衚珟するためにRustがすでに甚意しおいる語圙を䜿甚するこずは理にかなっおいたす。 それは私のひざのけいれん反応でした、そしおそれは他の倚くの人々にずっおの反応のようです。 それでは、このようにしないこずに぀いおの議論を繰り返し、それらに反論できるかどうかを芋おみたしょう。

  • 必芁な範囲の遞択は、新しい特性を必芁ずするほど斬新であり、特に最も䞀般的な範囲であるRange陀倖したす。

    • @ jturner314によっお提䟛される新しい実装を䜿甚しお、排他範囲の倀を正しく返すために、 Ord + Stepなどの特定のRange*タむプにさらに制限を远加できるようになりたした。 したがっお、排他的な範囲クランプは実際には必芁ないこずがよくありたすが、これらの技術的制限がない範囲のむンタヌフェむスを損なうこずなく、ここで範囲の党範囲を実際に受け入れるこずができたす。
  • 片偎クランプには、Infinity / Min / Maxを䜿甚できたす。

    • それは真実であり、この倉曎が私の意芋では本圓に匷力な矩務ではない理由の倧郚分です。 これに察する答えは1぀しかありたせん。぀たり、 Range*構文では、このナヌスケヌスの文字数ずむンポヌト数が少なくなりたす。

これを行わない理由に反論したので、オプションは同等に芋えるため、このコメントには倉曎を加える動機がありたせん。 倉曎を加える動機を芋぀けたしょう。 私には1぀の理由しかありたせん。それは、このスレッドの䞀般的な意芋は、範囲ベヌスのアプロヌチが蚀語のセマンティクスを改善するずいうこずであるように思われるずいうこずです。 包括的ダブル゚ンドレンゞクランプだけでなく、 .min()や.max()などの機胜にも䜿甚できたす。

この考え方が、RFCをそのたた安定させるこずに賛成しおいる他の人々ず䜕らかの牜匕力を持っおいるかどうか私は興味がありたす。

Clampは他の蚀語ず非垞に䌌おいるため、珟圚の圢匏のたたにしおおく方がよいず思いたす。
プルリク゚スト58710に取り組んだずき、範囲ベヌスの実装を䜿甚しようずしたした。
しかし、 rust-lang / rfcs1961コメント は、暙準圢匏の方が優れおいるず私に確信させたした。

さびの数倀がどのように機胜するかに慣れおいない人々を混乱させないために、関数に#[must_use]属性を蚭定するこずは論理的だず思いたす。 ぀たり、誰かが次の誀ったコヌドを曞いおいるこずが簡単にわかりたす。

let mut x: f64 = some_number_source();
x.clamp(0.0, 1.0);
//Proceeds to assume that 0.0 <= x <= 1.0

䞀般に、rustは数倀に察しお(number).method()アプロヌチを取りたす他の蚀語はMath.Method(number)䜿甚したすが、これを念頭に眮いたずしおも、これがnumber倉曎する可胜性があるこずは論理的な仮定です。

[must_use]属性が最近远加され
@ Xaeroxe範囲ベヌスのクランプ甚の䜕かを思い぀いたのですか
今の機胜は他のさびの数倀関数に䞀番合うず思いたすので、たた安定させたいず思いたす。

珟時点では、レンゞベヌスのクランプを䜿甚する理由はありたせん。 はい、must_use属性を远加しお、安定化に取り組みたしょう。

@SimonSapin @scottmcm安定化プロセスを再開できたすか

@ jturner314が蚀ったように、Ordの代わりにPartialOrdにクランプを蚭定するず、フロヌトにも䜿甚できるので䟿利です。

この号には、すでに専門のf32::clampずf64::clampがありたす。

これが私がやろうずしおいるこずです

use num_traits::float::FloatCore;

struct Foo<T> (T);

impl<T: FloatCore> Foo<T> {
    fn foo(&self) -> T {
        self.0.clamp(1, 10)
    }
}

fn main() {
    let foo = Foo(15.3);
    println!("{}", foo.foo())
}

遊び堎ぞのリンク。

PartialOrdはフロヌトのみの特性ではありたせん。 float固有のメ゜ッドを䜿甚しおも、カスタムPartialOrdタむプでクランプを䜿甚できるようにはなりたせん。

珟圚の実装では、䜿甚しおいなくおもEqが必芁です。

PartialOrdの䞻な懞念は、保蚌が匱くなり、クランプの保蚌が匱くなるこずでした。 これをPartialOrdたいナヌザヌは、私が曞いた別の関数に興味があるかもしれたせんhttps://docs.rs/num/0.2.1/num/fn.clamp.html

これらの保蚌は䜕ですか

かなり自然な期埅があるこずIFF x.clamp(a, b) == xその埌、 a <= x && x <= b 。 これはPartialCmpでは保蚌されたせん。 xはaたたはbず比范できない堎合がありたす。

挠然ず芚えおいるclamp()を探しお今日ここに来お、興味を持っお議論を読んだ。

任意の範囲を蚱可するこずず、いく぀かの名前付き関数を䜿甚するこずの間の劥協案ずしお、「オプショントリック」を䜿甚するこずをお勧めしたす。 これは䞀郚の人には人気がないこずは知っおいたすが、ここでは目的のセマンティクスをうたく捉えおいるようです。

#![allow(unstable_name_collisions)]

pub trait Clamp: Sized {
    fn clamp<L, U>(self, lower: L, upper: U) -> Self
    where
        L: Into<Option<Self>>,
        U: Into<Option<Self>>;
}

impl Clamp for f32 {
    fn clamp<L, U>(self, lower: L, upper: U) -> Self
    where
        L: Into<Option<Self>>,
        U: Into<Option<Self>>,
    {
        let below = match lower.into() {
            None => self,
            Some(lower) => self.max(lower),
        };
        match upper.into() {
            None => below,
            Some(upper) => below.min(upper),
        }
    }
}

#[test]
fn test_clamp() {
    assert_eq!(1.0, f32::clamp(2.0, -1.0, 1.0));
    assert_eq!(-1.0, f32::clamp(-2.0, -1.0, 1.0));
    assert_eq!(1.0, f32::clamp(2.0, None, 1.0));
    assert_eq!(-1.0, f32::clamp(-2.0, -1.0, None));
    assert_eq!(2.0, f32::clamp(2.0, -1.0, None));
    assert_eq!(-2.0, f32::clamp(-2.0, None, 1.0));
}

これがstd含たれおいる堎合、包括的実装もT: Ordに含めるこずができたす。これは、䞀般的なPartialOrd実装に関しお提起された懞念をカバヌしたす。

ナヌザヌコヌドでclamp()関数を定矩するず、珟圚、デフォルトで䞍安定な名前の衝突に関するコンパむラ譊告が生成されるこずを考えるず、この関数には「クランプ」ずいう名前で問題ないず思いたす。

clamp(a,b,c)はmin(max(a,b), c)ず同じように動䜜するはずだず思いたす。
以来maxずminために実装されおいたせんPartialOrdでもないはずですclamp 。
NaN問題に぀いおはすでに

@EdorianDark同意したす。 min、maxもPartialOrdのみを必芁ずしたす。

@noonien minずmaxはRust 1.0以降で定矩されおおり、 Ordが必芁で、 f32ずf64定矩がありたす。
これは、これらの機胜に぀いお議論するのに適切な堎所ではありたせん。
ここでは、 min 、 max 、およびclampが同等に動䜜し、驚くこずではないこずに泚意する必芁がありたす。
線集 PartialOrdの状況は気に入らず、 float Ord実装しおもらいたいのですが、1.0以降は倉曎できたせん。

これは統合され、玄1幎半の間䞍安定になっおいたす。 これを安定させるこずに぀いおどう思いたすか

これを安定させたいです

clampメ゜ッド名の競合が問題のように思われる堎合は、 https //github.com/rust-lang/rust/pull/66852#issuecomment-561667812のある時点で名前解決を倉曎するこずをお勧めし

@Xaeroxeプロセスは、安定化PRを提出し、それに぀いおlibsチヌムのコンセンサスを求めるこずだず思いたす。 t-libsが過負荷になっおいお、fcped以倖のものに远い぀いおいないようです。

さお、それはhttps://github.com/rust-lang/rust/pull/77872でしたか

@matkladは、実際にはFCPの提案が昚幎https://github.com/rust-lang/rust/issues/44095#issuecomment -544393395ですでに開始されおい

その堎合、問題に぀いお幎に1回皋床pingを実行するこずはかなり蚱容できるず思いたす。

@キムンディ
@sfackler
@withoutboats

https://github.com/rust-lang/rust/issues/44095#issuecomment-544393395はただあなたの泚意を埅っおいたす

FCPが開始されおから、libsチヌムはかなり倉化したした。 安定化PRで新しいFCPを開始するこずに぀いお、皆さんはどう思いたすか ここで残りのチェックボックスを埅぀よりも長くはかからないように感じたす。

@LukasKalbertodt元気です、キックオフしおもよろしいですか

FCPが安定化PRで発生したため、ここでFCPをキャンセルしたす //github.com/rust-lang/rust/pull/77872#issuecomment -722982535

@fcpbotキャンセル

ええず

@rfcbotキャンセル

@ m-ou-seの提案はキャンセルされたした。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡