メインコンテンツまでスキップ
Examples Verified (100%)

交差型

準備中

この機能は将来のリリースで計画されています。

交差型を使用すると、複数の型を1つに結合し、各結合された型のすべてのプロパティとメソッドを持つ型を作成できます。交差型を「AND」関係と考えてください—値は交差のすべての型を満たす必要があります。

交差型の理解

ユニオン型が「どちらか」の関係(A | Bは「AまたはB」)を表すのに対し、交差型は「かつ」の関係(A & Bは「AかつB」)を表します。

ユニオン vs 交差

# ユニオン型: 値はStringまたはIntegerのどちらか
type StringOrInt = String | Integer
value1: StringOrInt = "hello" # OK
value2: StringOrInt = 42 # OK

# 交差型: 値は両方の型のプロパティを持つ必要がある
type NamedAndAged = Named & Aged
# name(Namedから)とage(Agedから)の両方が必要

基本的な交差構文

交差演算子は&です:

type Combined = TypeA & TypeB & TypeC

インターフェースの結合

交差型の最も一般的な使用法はインターフェースの結合です:

# 個別のインターフェースを定義
interface Named
def name: String
end

interface Aged
def age: Integer
end

interface Contactable
def email: String
def phone: String
end

# 交差でインターフェースを結合
type Person = Named & Aged
type Employee = Named & Aged & Contactable

# 交差を実装するクラスはすべてのインターフェースを実装する必要がある
class User
implements Named, Aged

@name: String
@age: Integer

def initialize(name: String, age: Integer): void
@name = name
@age = age
end

def name: String
@name
end

def age: Integer
@age
end
end

# UserはPerson型として使用可能
user: Person = User.new("Alice", 30)
puts user.name # OK: Namedインターフェース
puts user.age # OK: Agedインターフェース

型とインターフェースの混合

インターフェースをクラス型と結合できます:

# 基本クラス
class Entity
@id: Integer

def initialize(id: Integer): void
@id = id
end

def id: Integer
@id
end
end

# インターフェース
interface Timestamped
def created_at: Time
def updated_at: Time
end

# クラスとインターフェースの交差
type TimestampedEntity = Entity & Timestamped

# 実装はEntityを拡張しTimestampedを実装する必要がある
class User < Entity
implements Timestamped

@name: String
@created_at: Time
@updated_at: Time

def initialize(id: Integer, name: String): void
super(id)
@name = name
@created_at = Time.now
@updated_at = Time.now
end

def created_at: Time
@created_at
end

def updated_at: Time
@updated_at
end
end

# Userは交差型を満たす
user: TimestampedEntity = User.new(1, "Alice")
puts user.id # Entityクラスから
puts user.created_at # Timestampedインターフェースから

実用的な例

ミックスインパターン

交差型はRubyのミックスイン概念とうまく機能します:

# 機能インターフェースを定義
interface Serializable
def to_json: String
def self.from_json(json: String): self
end

interface Validatable
def valid?: Boolean
def errors: Array<String>
end

interface Persistable
def save: Boolean
def delete: Boolean
end

# 必要に応じて機能を結合
type Model = Serializable & Validatable & Persistable

# フル機能のモデルクラス
class Article
implements Serializable, Validatable, Persistable

@title: String
@content: String
@errors: Array<String>

def initialize(title: String, content: String): void
@title = title
@content = content
@errors = []
end

def to_json: String
"{ \"title\": \"#{@title}\", \"content\": \"#{@content}\" }"
end

def self.from_json(json: String): Article
# JSONをパースしてインスタンスを作成
Article.new("Title", "Content")
end

def valid?: Boolean
@errors = []
@errors.push("Title cannot be empty") if @title.empty?
@errors.push("Content cannot be empty") if @content.empty?
@errors.empty?
end

def errors: Array<String>
@errors
end

def save: Boolean
return false unless valid?
# データベースに保存
true
end

def delete: Boolean
# データベースから削除
true
end
end

# ArticleはModel交差型を満たす
article: Model = Article.new("Hello", "World")
puts article.to_json # Serializable
puts article.valid? # Validatable
article.save # Persistable

リポジトリパターン

interface Identifiable
def id: Integer | String
end

interface Timestamped
def created_at: Time
def updated_at: Time
end

interface SoftDeletable
def deleted?: Boolean
def deleted_at: Time | nil
end

# さまざまなニーズに合わせた組み合わせ
type BaseEntity = Identifiable & Timestamped
type DeletableEntity = Identifiable & Timestamped & SoftDeletable

class Repository<T: BaseEntity>
@items: Array<T>

def initialize: void
@items = []
end

def find(id: Integer | String): T | nil
@items.find { |item| item.id == id }
end

def all: Array<T>
@items.dup
end

def recent(limit: Integer = 10): Array<T>
@items.sort_by { |item| item.created_at }.reverse.take(limit)
end
end

class SoftDeleteRepository<T: DeletableEntity> < Repository<T>
def all: Array<T>
@items.reject { |item| item.deleted? }
end

def with_deleted: Array<T>
@items.dup
end

def only_deleted: Array<T>
@items.select { |item| item.deleted? }
end
end

イベントシステム

interface Event
def event_type: String
def timestamp: Time
end

interface Cancellable
def cancelled?: Boolean
def cancel: void
end

interface Prioritized
def priority: Integer
end

# さまざまな機能を持つイベントタイプ
type BasicEvent = Event
type CancellableEvent = Event & Cancellable
type PrioritizedCancellableEvent = Event & Cancellable & Prioritized

class UserClickEvent
implements Event

@event_type: String
@timestamp: Time

def initialize: void
@event_type = "user_click"
@timestamp = Time.now
end

def event_type: String
@event_type
end

def timestamp: Time
@timestamp
end
end

class NetworkRequestEvent
implements Event, Cancellable

@event_type: String
@timestamp: Time
@cancelled: Boolean

def initialize: void
@event_type = "network_request"
@timestamp = Time.now
@cancelled = false
end

def event_type: String
@event_type
end

def timestamp: Time
@timestamp
end

def cancelled?: Boolean
@cancelled
end

def cancel: void
@cancelled = true
end
end

class CriticalAlertEvent
implements Event, Cancellable, Prioritized

@event_type: String
@timestamp: Time
@cancelled: Boolean
@priority: Integer

def initialize(priority: Integer): void
@event_type = "critical_alert"
@timestamp = Time.now
@cancelled = false
@priority = priority
end

def event_type: String
@event_type
end

def timestamp: Time
@timestamp
end

def cancelled?: Boolean
@cancelled
end

def cancel: void
@cancelled = true
end

def priority: Integer
@priority
end
end

# さまざまなイベントタイプのイベントハンドラ
def handle_basic_event(event: BasicEvent): void
puts "Event: #{event.event_type} at #{event.timestamp}"
end

def handle_cancellable_event(event: CancellableEvent): void
if event.cancelled?
puts "Event #{event.event_type} was cancelled"
else
puts "Processing #{event.event_type}"
end
end

def handle_priority_event(event: PrioritizedCancellableEvent): void
puts "Priority #{event.priority}: #{event.event_type}"
event.cancel if event.priority < 5
end

ジェネリクスとの交差

交差型はジェネリクスと組み合わせることができます:

# 交差制約を持つジェネリック型
def process<T: Serializable & Validatable>(item: T): Boolean
if item.valid?
json = item.to_json
# APIに送信
true
else
puts "Validation errors: #{item.errors.join(', ')}"
false
end
end

# 複数の機能を必要とするコレクション
class ValidatedCollection<T: Identifiable & Validatable>
@items: Array<T>

def initialize: void
@items = []
end

def add(item: T): Boolean
if item.valid?
@items.push(item)
true
else
false
end
end

def find(id: Integer | String): T | nil
@items.find { |item| item.id == id }
end

def all_valid: Array<T>
@items.select { |item| item.valid? }
end

def all_invalid: Array<T>
@items.reject { |item| item.valid? }
end
end

型ガードとナローイング

交差型は型ナローイングと連携します:

interface Animal
def speak: String
end

interface Swimmable
def swim: void
end

interface Flyable
def fly: void
end

type Duck = Animal & Swimmable & Flyable

class DuckImpl
implements Animal, Swimmable, Flyable

def speak: String
"Quack!"
end

def swim: void
puts "Swimming..."
end

def fly: void
puts "Flying..."
end
end

def test_duck(animal: Animal): void
puts animal.speak

# responds_to?での型ナローイング
if animal.responds_to?(:swim) && animal.responds_to?(:fly)
# ここでanimalはDuck (Animal & Swimmable & Flyable)として扱われる
duck = animal as Duck
duck.swim
duck.fly
end
end

競合と解決

交差型に競合するメンバーがある場合、より具体的な型が勝ちます:

interface HasName
def name: String
end

interface HasOptionalName
def name: String | nil
end

# 交差はより制限的な型を要求
type Person = HasName & HasOptionalName
# person.nameはStringでなければならない(String | nilではない)
# StringがString | nilより具体的であるため

class User
implements HasName, HasOptionalName

@name: String

def initialize(name: String): void
@name = name
end

# 両方のインターフェースを満たすためにStringを返す必要がある
def name: String
@name
end
end

ベストプラクティス

1. 小さく焦点を絞ったインターフェースを構成

# 良い:単一責任の小さなインターフェース
interface Identifiable
def id: Integer
end

interface Named
def name: String
end

interface Timestamped
def created_at: Time
end

type Entity = Identifiable & Named & Timestamped

# あまり良くない:大きく一体的なインターフェース
interface Entity
def id: Integer
def name: String
def created_at: Time
def updated_at: Time
def save: Boolean
def delete: Boolean
# 責任が多すぎる
end

2. 意味のある名前を使用

# 良い:交差が何を表すか明確
type AuditedEntity = Entity & Auditable
type SerializableModel = Model & Serializable

# あまり良くない:一般的な名前
type TypeA = Interface1 & Interface2
type Combined = Foo & Bar

3. 過度に複雑にしない

# 良い:適切な数の交差
type FullModel = Identifiable & Timestamped & Validatable

# 潜在的に問題:交差が多すぎる
type SuperType = A & B & C & D & E & F & G & H
# 実装と理解が困難

4. 意図を文書化

# 良い:なぜ交差が必要かを説明するコメント
# シリアライズ可能でキャッシュ可能なエンティティを表す
type CacheableEntity = Serializable & Identifiable

# キャッシュ実装
class Cache<T: CacheableEntity>
@store: Hash<Integer | String, String>

def set(entity: T): void
@store[entity.id] = entity.to_json
end

def get(id: Integer | String): String | nil
@store[id]
end
end

一般的なパターン

ビルダーパターン

interface Buildable
def build: self
end

interface Validatable
def valid?: Boolean
end

interface Resettable
def reset: void
end

type CompleteBuilder = Buildable & Validatable & Resettable

class FormBuilder
implements Buildable, Validatable, Resettable

@fields: Hash<String, String>
@errors: Array<String>

def initialize: void
@fields = {}
@errors = []
end

def add_field(name: String, value: String): self
@fields[name] = value
self
end

def build: self
self
end

def valid?: Boolean
@errors = []
@errors.push("No fields") if @fields.empty?
@errors.empty?
end

def reset: void
@fields = {}
@errors = []
end
end

ステートマシン

interface State
def name: String
end

interface Transitionable
def can_transition_to?(state: String): Boolean
def transition_to(state: String): void
end

interface Observable
def on_enter: void
def on_exit: void
end

type ManagedState = State & Transitionable & Observable

class WorkflowState
implements State, Transitionable, Observable

@name: String
@allowed_transitions: Array<String>

def initialize(name: String, allowed_transitions: Array<String>): void
@name = name
@allowed_transitions = allowed_transitions
end

def name: String
@name
end

def can_transition_to?(state: String): Boolean
@allowed_transitions.include?(state)
end

def transition_to(state: String): void
if can_transition_to?(state)
on_exit
# 遷移を実行
on_enter
else
raise "Invalid transition from #{@name} to #{state}"
end
end

def on_enter: void
puts "Entering state: #{@name}"
end

def on_exit: void
puts "Exiting state: #{@name}"
end
end

制限事項

プリミティブ型は交差できない

# 意味がない - 値はStringでありながら同時にIntegerではありえない
# type Impossible = String & Integer # 空の型になる

# 交差は構造型(インターフェース、クラス)で意味がある
type Valid = Interface1 & Interface2

実装要件

# 交差を使用する場合、実装はすべての部分を満たす必要がある
type Complete = Interface1 & Interface2 & Interface3

class MyClass
# Interface1、Interface2、Interface3すべてを実装する必要がある
implements Interface1, Interface2, Interface3
# ...
end

次のステップ

交差型を理解したので、次を探索してください: