質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Generics

Genericsはパラメトリックなポリモーフィズムの形態であり、.NET やJavaなど、様々な言語に実装されています。C++のテンプレートと同等の機能を持ち合わせています。

関数型プログラミング

関数型プログラミングとは、関数を用いて演算子を構築し、算出し、コンピュータプログラムを構成する枠組みです。

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

Q&A

解決済

1回答

1143閲覧

Rustでi32とu32を区別するためにUnsigedを型境界に使おうとするとconflictしてると怒られる

hidekiti

総合スコア23

Generics

Genericsはパラメトリックなポリモーフィズムの形態であり、.NET やJavaなど、様々な言語に実装されています。C++のテンプレートと同等の機能を持ち合わせています。

関数型プログラミング

関数型プログラミングとは、関数を用いて演算子を構築し、算出し、コンピュータプログラムを構成する枠組みです。

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

0グッド

0クリップ

投稿2021/08/17 01:37

編集2021/08/19 14:28

やりたいこと

UnsigedなやつとSignedなやつで関数のふるまいを変えたい

ソースコード

rust

1 2use std::{ops::Mul, process::Output}; 3use num::{Signed, Unsigned}; 4 5struct Sample<T>(T); 6// Unsigedなprimitive型に対する計算(負の場合を考慮しない) 7impl<T> Mul<u32> for Sample<T> { 8 type Output = Self; 9 fn mul(self, rhs: u32) -> Self::Output { 10 todo!() 11 } 12} 13// Signedなprimitive型に対する計算(負の場合も実装する) 14impl<S:Signed + 'static + Copy,T> Mul<S> for Sample<T> { 15 type Output = Self; 16 fn mul(self, rhs: S) -> Self::Output { 17 todo!() 18 } 19}

エラー

conflicting implementations of trait `std::ops::Mul<u32>` for type `Sample<_>` upstream crates may add a new impl of trait `num::Signed` for type `u32` in future versions

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tatsuya6502

2021/08/17 10:24 編集

こんにちは。いまある情報だけですと、エラーの原因も解決方法もわかりません。 質問に以下の情報を追記していただけないでしょうか? - エラーメッセージ - Negトレイトの定義 - 何かクレートを使用しているなら、その情報。(AsPrimitive, WrappingMul, Unsignedトレイトはnum-traitsクレートのものを使っているのですか?) - もしAsPrimitive, WrappingMul, Unsignedトレイトは自分で定義したものなら、それらの定義
hidekiti

2021/08/17 15:00

コメントありがとうございます。 すべてのtraitはnum-traitsクレートのものを使ってます。 Unsigedはi32は実装することはなく、u32はSignedを実装することがないことが人間にはわかりますが、コンパイラはわからないので、型境界にUnsignedをつけた型TについてのMul<T>の実装と、i32についてのMul<i32>の実装がコンフリクトするんです。 これをうまくコンフリクトさせずに分けて実装できる、択一型(e.g. Unsignedを実装したらSignedは実装できないし、逆も成り立つ)みたいな型境界はないんですかね。ないとしたら符号付き整数型と符号なし整数型で実装を分けるにはすべての型について実装するしかないですかね。
退会済みユーザー

退会済みユーザー

2021/08/17 16:31 編集

まずは、tatsuya6502さんの質問にちゃんと応えましょう(念の為、回答者が偉いから従えとかいうことではなく、至極妥当な確認事項だからです). あと、u32にstd::ops::Negは実装されていないので、その2つの実装がコンフリクトするとは思えません.できれば、ソースコードもあまり省略せずに貼ってほしいです.塩梅が難しいかもしれませんが、不足しているよりは過剰な方が回答しやすいです.
hidekiti

2021/08/19 14:16

上のソースコードは変更してしまって手元になくなってしまいました。ごめんなさい。 ご指摘にのようにu32はNegを現状実装していませんが、コンパイラはu32がいつかNegを実装するかもしれないから潜在的にconflictしてるよと怒ってきます。これに対処する方法をご存じないですか?
hidekiti

2021/08/19 14:34

tsutuya6502さんのご指摘のようにSignedなものとUnsigedなものの区別は型境界ではできなさそうなので、実装単位を分けることで対処しようかなと思います。
退会済みユーザー

退会済みユーザー

2021/08/19 16:45 編集

潜在的なconflictという概念があるんですね.それは知らなかったので、勉強になりました. unstableな機能としては、negative implsというのがありますが、unstableなので、nightlyでないとコンパイルできなくなりますし、あまりおすすめはしません. https://doc.rust-lang.org/beta/unstable-book/language-features/negative-impls.html
guest

回答1

0

ベストアンサー

前提

ご質問のコードに、省略されているDecimal構造体やuse文を追加してみましたが、エラーは再現できませんでした。そこで、質問の追記依頼の欄にあるコメントを頼りに、以下のようにコードを変更したところ、それらしいエラーが出ました。

  • impl Mul<u32> for Decimal<u32>impl Mul<i32> for Decimal<i32>に変更

当方でエラーを再現できたコードは以下のとおりです。このコードを元に回答します。

rust

1// Cargo.toml 2// 3// [dependencies] 4// num-traits = "0.2" 5 6use std::ops::{Mul, Neg}; 7use num_traits::{AsPrimitive, ToPrimitive, Unsigned, WrappingMul}; 8 9struct Decimal<T>(T); 10 11impl Mul<i32> for Decimal<i32> { 12 type Output = Self; 13 fn mul(self, rhs: u32) -> Self::Output { 14 Decimal(self.0.wrapping_mul(rhs.to_i32().unwrap())) 15 } 16} 17 18impl<S, T> Mul<S> for Decimal<T> 19where 20 S: 'static + Neg<Output = S> + Copy, 21 T: AsPrimitive<S> + WrappingMul + Unsigned, 22{ 23 type Output = Self; 24 fn mul(self, rhs: S) -> Self::Output { 25 // コンパイルエラーになるためコメントアウト 26 // error[E0308]: mismatched types: 27 // expected type parameter `S`, found type `{integer}` 28 // if rhs < 0 { 29 // // error[E0369]: cannot multiply `Decimal<T>` by `u32` 30 // // error[E0605]: non-primitive cast: `S` as `u32` 31 // -(self * rhs as u32) 32 // } else { 33 // self * rhs as u32 34 // } 35 todo!() 36 } 37}

また、エラーメッセージは以下のとおりです。

console

1error[E0119]: conflicting implementations of trait `Mul<i32>` for type `Decimal<i32>` 2 | 318 | impl Mul<i32> for Decimal<i32> { 4 | ------------------------------ first implementation here 5... 633 | / impl<S, T> Mul<S> for Decimal<T> 734 | | where 835 | | S: 'static + Neg<Output = S> + PartialOrd + Copy, 936 | | T: AsPrimitive<S> + WrappingMul + Unsigned, 10... | 1151 | | } 1252 | | } 13 | |_^ conflicting implementation for `Decimal<i32>` 14 | 15 = note: upstream crates may add a new impl of trait `num_traits::Unsigned` for type `i32` in future versions

質問の回答

質問の追記依頼の欄のコメントより

Unsigedi32は実装することはなく、u32Signedを実装することがないことが人間にはわかりますが、コンパイラはわからないので、型境界にUnsignedをつけた型TについてのMul<T>の実装と、i32についてのMul<i32>の実装がコンフリクトするんです。
これをうまくコンフリクトさせずに分けて実装できる、択一型(e.g. Unsignedを実装したらSignedは実装できないし、逆も成り立つ)みたいな型境界はないんですかね。

現時点のRustでは択一型を定義したり、否定のようなトレイト境界をつけることはできないと思います。そのためDecimal<i32>Decimal<T: Unsigned>がコンフリクトするのは避けられません。

回避方法ですが、Decimal<T>を以下の2つの型に分けるのはどうでしょうか?

rust

1struct UnsignedDecimal<T: Unsigned>(T); 2struct SignedDecimal<T: Signed>(T);

これを用いると以下のようなコードになり、コンフリクトを回避できます。

rust

1use std::ops::{Mul, Neg}; 2use num_traits::{AsPrimitive, Signed, ToPrimitive, Unsigned, WrappingMul}; 3 4struct UnsignedDecimal<T: Unsigned>(T); 5struct SignedDecimal<T: Signed>(T); 6 7impl Mul<i32> for SignedDecimal<i32> { 8 type Output = Self; 9 fn mul(self, rhs: i32) -> Self::Output { 10 SignedDecimal(self.0.wrapping_mul(rhs.to_i32().unwrap())) 11 } 12} 13 14impl<S, T> Mul<S> for UnsignedDecimal<T> 15where 16 S: 'static + Neg<Output = S> + Copy, 17 T: AsPrimitive<S> + WrappingMul + Unsigned, 18{ 19 type Output = Self; 20 fn mul(self, rhs: S) -> Self::Output { 21 todo!() 22 } 23}

投稿2021/08/17 17:03

編集2021/08/18 23:21
tatsuya6502

総合スコア2046

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hidekiti

2021/08/19 14:29

回答ありがとうございます。 やはり型推論で分けるのは今はできないということなんですね。 unsigned_mulトレイトとかを作ってそれを使う方針でしてみようかな と思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問