---
title: Send と Sync
url: https://doc.liz6.com/ja/rust/06-concurrency-and-asynchrony/01-Send-Sync
locale: ja
area: rust
tags:
- rust
- concurrency-and-asynchrony
date: 2026-06-30
modified: 2026-07-16
description: Send と Sync は Rust の並行安全性の基盤です。Send は所有権をスレッド間で移動可能にし、Sync は参照をスレッド間で共有可能にします。これらは auto trait（コンパイラによる自動推論）であり、ある型のすべてのフィールドが Send であれば、その型も自動的に Send となります。PhantomData は、自動推論を手動で抑制または復元するために使用され、不安全コードや FFI において極めて重要です。
---

# Send と Sync

> Send と Sync は Rust の並行安全性の基盤です。Send は所有権をスレッド間で移動可能にし、Sync は参照をスレッド間で共有可能にします。これらは auto trait（コンパイラによる自動推論）であり、ある型のすべてのフィールドが Send であれば、その型も自動的に Send となります。PhantomData は、自動推論を手動で抑制または復元するために使用され、不安全コードや FFI において極めて重要です。

## Send と Sync とは

`Send` と `Sync` は Rust の並行安全性の中核をなすものです。これらはコンパイル時のマーカートレイトであり、ある型がスレッド間で使用可能かどうかを示します。

**`Send`**: この型の**所有権**をスレッド間で移動できます。ある型のすべてのフィールドが `Send` であれば、その型も `Send` となります——これはコンパイラによって自動で推論されます。`Rc<T>` は `Send` ではありません——参照カウント操作がアトミックではないため、別のスレッドに移動するとカウントが壊れる可能性があります。

**`Sync`**: この型を**共有参照**（`&T`）経由でスレッド間でアクセスできます。形式的な定義は次の通りです：`T: Sync` であるための必要十分条件は `&T: Send` です。`RefCell<T>` は `Sync` ではありません——実行時の借用チェックがスレッドセーフであるとは保証されないためです。`Mutex<T>` は `Sync` です（`T: Send` の場合）——Mutex は内部をロックで保護し、複数のスレッドが `&Mutex<T>` 経由で安全にアクセスできるようにします。

## コンパイラによる推論

コンパイラは型の各フィールドをチェックします。すべてのフィールドが `Send` であれば、その型は自動的に `Send` となります。すべてのフィールドが `Sync` であれば、その型は自動的に `Sync` となります。これらの属性を失うのは、**裸のポインタ**（`*const T`, `*mut T`）や**スレッドセーフでないプリミティブ**（`Rc`, `RefCell`, `Cell`, `UnsafeCell`）を導入した場合のみです。

```rust
fn assert_send<T: Send>() {}
assert_send::<i32>();                // OK
assert_send::<Arc<String>>();        // OK (Arc はアトミック操作で同期)
// assert_send::<Rc<String>>();      // コンパイルエラー
// assert_send::<*const i32>();      // コンパイルエラー — 裸のポインタは所有権セマンティクスを持たない

fn assert_sync<T: Sync>() {}
assert_sync::<Mutex<i32>>();         // OK (Mutex は内部同期を保証)
// assert_sync::<RefCell<i32>>();    // コンパイルエラー
```

## PhantomData による手動制御

裸のポインタを使用してカスタムコンテナを実装する場合、裸のポインタ自体は Send/Sync の属性を持ちません。しかし、論理的にはこれらの保証があるかもしれません：

```rust
use std::marker::PhantomData;
use std::rc::Rc;

struct MyNonSend {
    data: i32,
    _not_send: PhantomData<Rc<()>>,  // マーク：この型は Send ではない（Rc の属性を継承）
}
// MyNonSend の内部には i32（Send である）しかないが、PhantomData<Rc<()>> により !Send となる
```

PhantomData はメモリを消費しません（ZST: Zero-Sized Type）。型レベルでのみマーキングを行います。unsafe コードの作者は、PhantomData を使用して「この型は Send/Sync であるべき／であるべきではない」ということをコンパイラに伝え、コンパイラが呼び出し側に対して正当性のチェックを行うようにします。

## なぜ「すべての型がデフォルトで Send」ではないのか

標準ライブラリの型は慎重に設計されています。`Rc<T>` は本質的に Send ではなく、`Mutex<T>` は本質的に Sync です。サードパーティ製のライブラリにおいて、内部可変性を導入する型は、Send/Sync の伝播を慎重に検討する必要があります。ある型が実際にはスレッドセーフではないのに、誤って Send となってしまうと、それはデータ競合の抜け穴となってしまいます。この「自動推論＋人間の介入が可能」という設計により、Rust はパフォーマンス（ゼロオーバーヘッド）と安全性（コンパイル時の保証）のバランスを取っています。

## 参考

- **Rustonomicon**: Send and Sync
- **Rust Reference**: auto traits

*Keywords: Send, Sync, auto trait, PhantomData, thread safety, marker type, Rc, RefCell*
