uniquis
@uniquis

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

複数のトレイト境界を持つ変数の記述方法

Q&A

解決したいこと

Rustで複数のトレイト境界を持つ変数について記述する方法を知りたいです。
具体的なコードを以下に示します。

Sample Code

まず、oracleクレートを使用しています。query_namedメソッドのoracleクレートでのサンプルコードは以下のとおりです。

pub fn query_named(
    &self,
    sql: &str,
    params: &[(&str, &dyn ToSql)]
) -> Result<ResultSet<'_, Row>>

conn.query_named("insert into emp(empno, ename) values (:id, :name)",
                   &[("id", &114),
                     ("name", &"Smith")])?;

この引数params部分について、エラーがあったときに表示させたいという要望がチーム内から出てきました。
paramsを変数として切り出すと次のようになります。

let params: [(&str, &dyn ToSql);2] = [("id", &114), ("name", &"Smith")];
conn.query_named("insert into emp(empno, ename) values (:id, :name)", &params)?;

paramsと同じ形式を引数に取って文字列にするため、次のようにparams2String関数を作成しました。

fn param2string(params: &[(&str, &dyn Display)]) -> String {
  params
  .iter()
  .map(|p| format!("{} = {}", p.0, p.1))
  .collect::<Vec<_>>()
  .join(", ")
}

assert_eq!("id = 114, name = Smith", param2string(&[("id", &114), ("name", &"Smith")]));

param2Stringparams引数を変数として切り出すと次のようになります。

let params: [(&str, &dyn Display);2] = [("id", &114), ("name", &"Smith")];
assert_eq!("id = 114, name = Smith", param2string(&params));

ということで、次の???部分を完成させれば目的を達成できるのでは、という状態になりました。

let params: [(&str, &dyn ???);2] = [("id", &114), ("name", &"Smith")];

conn.query_named("insert into emp(empno, ename) values (:id, :name)", &params)?;
assert_eq!("id = 114, name = Smith", param2string(&params));

試したこと

さしあたり、VSCodeのIntelliSenceでは次のようなコードが例示されました。

let params: [(&str, &dyn (ToSql + Display));2] = [("id", &114), ("name", &"Smith")];

conn.query_named("insert into emp(empno, ename) values (:id, :name)", &params)?;
assert_eq!("id = 114, name = Smith", param2string(&params));

しかし、これはコンパイルエラーになります。

only auto traits can be used as additional traits in a trait object

additional non-auto trait

help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: oracle::sql_type::ToSql + std::fmt::Display {}`
note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>

helpに従ってNewTraitを作成してみます。

trait NewTrait: ToSql + Display{}

let params: [(&str, &(dyn NewTrait)); 2] = [("id", &114), ("name", &"Smith")];

integerToSqlDisplayのトレイト境界を満たしていますが、NewTraitのトレイト境界を満たしませんでした。

the trait bound `{integer}: NewTrait` is not satisfied

the trait `NewTrait` is not implemented for `{integer}`

note: required for the cast to the object type `dyn NewTrait`

確認できたのはここまでです。castもしましたが特にエラーメッセージが変わりませんし……
どなたか、このトレイト境界を満たす方法をお願いします。

0

1Answer

NewTrait の実装が必要です。

trait NewTrait: ToSql + Display {}

impl<T: ToSql + Display> NewTrait for T {}

としてください。

0Like

Your answer might help someone💌