## 概要
[[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();
}
```