## 概要 [[Rust]]では、[[オーファンルール]]を回避するため、[[ニュータイプパターン]]を使いたいシーンが出てくる。例えば[[String]]の[[Displayトレイト]]実装を書き換えたい場合を考える。 ```rust use std::fmt::{Display, Formatter}; // only traits defined in the current crate can be implemented for types defined outside of the crate [E0117] impl Display for String { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "**{}**", self) } } fn main() { let s = String::from("hoge"); eprintln!("s = {s}"); } ``` これは、[[Rustの外部トレイトは外部の型には実装できない]]制約に引っかかるためエラーになる。([[String]]は[[外部の型]]であり、[[Displayトレイト]]は[[外部トレイト]]) これを解決するため、[[外部の型]]を[[内部の型]]にすることで制約を回避する。具体的には[[ニュータイプパターン]]を使う。 ```rust use std::fmt::{Display, Formatter}; // タプル構造体としてラップ (ニュータイプパターン) struct WString(String); impl Display for WString { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "**{}**", self.0) } } fn main() { let s = WString(String::from("hoge")); eprintln!("s = {s}"); } ``` ## 問題 このコードベースでは`WString`を文字列のように扱いたい。つまり、[[String]]の[[メソッド (Rust)|メソッド]]を呼び出す機会が多くなる。だが、`WString`自体には[[メソッド (Rust)|メソッド]]が定義されていないため、以下のような冗長なコードになってしまう。 ```rust fn main() { let s = WString(String::from("hoge")); let a: &str = s.0.as_str(); } ``` `.0`の2文字なのでコード量が大きく増えるわけでない... がスマートに`.0`なしで書きたい。 ## 解決策 [[Derefトレイト]]を実装する。 ```rust impl Deref for WString { type Target = String; fn deref(&self) -> &Self::Target { &self.0 } } ``` これで以下のような記述が可能になる。 ```rust fn main() { let s = WString(String::from("hoge")); let a = s.as_str(); } ``` 余談だが、`WString`に[[関連関数]]として`from`を実装しておいた方が`WString`の初期化もシンプルになる。 ```rust use std::fmt::{Display, Formatter}; use std::ops::Deref; struct WString(String); impl WString { fn from(s: &str) -> Self { WString(String::from(s)) } } impl Display for WString { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "**{}**", self.0) } } impl Deref for WString { type Target = String; fn deref(&self) -> &Self::Target { &self.0 } } fn main() { let s = WString::from("hoge"); let a = s.as_str(); } ``` ## 仕組み sは`WString`型だ。 ```rust let s: WString = WString::from("hoge"); ``` そのままでは単なる[[タプル構造体]]に過ぎない。`starts_with`[[メソッド (Rust)|メソッド]]はないとエラーになってしまうだろう。 ```rust struct WString(String); ``` だが、以下の[[Derefトレイト]]実装が功をなす。 ```rust impl Deref for WString { type Target = String; fn deref(&self) -> &Self::Target { &self.0 } } ``` もう一度先ほどのコードを見てみよう。 ```rust fn main() { let s: WString = WString::from("hoge"); // sがWString型なのにString型のas_strメソッドが呼べるのはなぜ..? let a = s.as_str(); } ``` ここで[[String]]の`as_str`がもつシグニチャを改めて確認してみよう。 ```rust impl String { // 中略 pub fn as_str(&self) -> &str ``` 第1引数は`self`の[[参照]]になるのだ。この場合は`&String`だ。 ここで、[[参照外し型強制]]により`&WString`は`&String`に型強制される。データ型`WString`が`Deref<Target=String>`を実装しているからだ。それゆえ以下のコードが成立する。 ```rust fn main() { let s: WString = WString::from("hoge"); // s.as_str()はas_str(&WString) // as_str(&WString)は参照外し型強制により... // as_str(&String)と型強制される // これはStringのas_strメソッドに合致するので、s.as_strは呼び出し可能 let a = s.as_str(); } ```