Opaque Type: چیست، some و any در Swift

نویسنده: IT Sectr منتشر شده: 2026-06-18 زمان مطالعه: 11 دقیقه

Opaque Type (نوع ناپیدا) — مکانیزمی در Swift است که به تابع اجازه می‌دهد مقداری از یک نوع را برگرداند بدون اینکه نوع مشخص را به کد فراخواننده فاش کند. کلمه کلیدی some در نوع برگشتی — معروف‌ترین مثال: some View در SwiftUI به معنای «یک نوع منطبق بر View برگردانده می‌شود، اما دقیقاً کدام — جزئیات پیاده‌سازی است» می‌باشد. Opaque type هویت نوع را حفظ می‌کند (برخلاف پروتکل به عنوان نوع)، که به کامپایلر اجازه می‌دهد کد را بهینه‌سازی کند و سازگاری نوع برگشتی را تضمین می‌کند. به نقل از Swift Book, 2025، opaque types مشکل پروتکل‌های دارای associated types را حل می‌کنند و امکان بازگرداندن مقادیر این پروتکل‌ها را از توابع فراهم می‌کنند.

نکات اصلی

  • Opaque Type — نوع برگشتی که پیاده‌سازی مشخص را از کد فراخواننده پنهان می‌کند
  • some — کلمه کلیدی برای اعلام opaque type در موقعیت برگشتی
  • هویت نوع حفظ می‌شود: کامپایلر نوع مشخص را می‌داند، برخلاف any
  • SwiftUI از some View به عنوان روش استاندارد اعلام body استفاده می‌کند
  • محدودیت: تابع با some باید از همه شاخه‌ها همان نوع مشخص را برگرداند

Opaque Type در Swift چیست؟

Opaque Type — نوع برگشتی است که با کلمه کلیدی some اعلام شده و پیاده‌سازی مشخص را از کد فراخواننده پنهان می‌کند. طرف فراخواننده فقط می‌داند که مقدار برگشتی با یک پروتکل خاص مطابقت دارد، اما نمی‌داند دقیقاً چه نوعی پشت some قرار دارد. در عین حال کامپایلر نوع دقیق را می‌داند و از آن برای توزیع ایستا و بهینه‌سازی استفاده می‌کند.

مسئله‌ای که Opaque Type حل می‌کند

قبل از ظهور opaque types در Swift 5.1 (SE-0244) بازگرداندن پروتکل دارای associated types از یک تابع بدون جعبه پیچی (boxing) غیرممکن بود. به عنوان مثال، پروتکل Equatable دارای associated type است و تابع نمی‌توانست به سادگی Equatable را برگرداند — کامپایلر خطای «protocol can only be used as a generic constraint» می‌داد. Opaque type این مشکل را حل کرد.

swift
func makeInt() -> some Equatable {
    return 42
}

func makeString() -> some Equatable {
    return "Hello"
}

// کامپایلر می‌داند که makeInt Int برمی‌گرداند
// makeInt() == makeString() — ❌ خطا، انواع متفاوت

هر دو تابع some Equatable برمی‌گردانند، اما انواع مشخص متفاوت هستند: Int و String. تلاش برای مقایسه آنها با == باعث خطای کامپایل می‌شود، زیرا opaque type تضمین می‌کند که از یک فراخوانی خاص همان نوع برگردانده می‌شود، اما نه بین توابع مختلف. این یک ویژگی است نه باگ: opaque type هویت نوع را جایی که پروتکل به عنوان نوع (any Equatable) آن را از دست می‌دهد حفظ می‌کند.

Opaque Type vs Generic: تفاوت در چیست

Generic و Opaque Type — دو روی یک سکه هستند. Generic به کد فراخواننده اجازه می‌دهد نوع را انتخاب کند، در حالی که opaque type به تابع اجازه می‌دهد نوع را از کد فراخواننده پنهان کند. تفاوت در جهت کنترل است.

ویژگیGeneric <T>Opaque some
چه کسی نوع را انتخاب می‌کندکد فراخوانندهتابع/متد
هویت نوعحفظ می‌شود (پایدار)حفظ می‌شود (پایدار)
تعداد شاخه‌های returnیک (از طریق generic)همان نوع در همه شاخه‌ها
کاربردالگوریتم‌ها، ساختارهای دادهSwiftUI، روش‌های کارخانه

Generic — انتخاب بیرونی

در تابع generic، caller تصمیم می‌گیرد از چه نوعی استفاده کند. تابع باید با هر T که محدودیت‌ها را برآورده می‌کند کار کند. برای opaque type، caller نوع مشخص را نمی‌داند — تصمیم را پیاده‌سازی می‌گیرد.

swift
// Generic: caller نوع را انتخاب می‌کند
func identity<T>(_ value: T) -> T { value }
let x: Int = identity(42)

// Opaque: تابع نوع را پنهان می‌کند
func makeSomeEquatable() -> some Equatable { 42 }
let y = makeSomeEquatable()

انتخاب بین generic و opaque type به نیت بستگی دارد. اگر کد فراخواننده باید نوع را انتخاب کند — از generic استفاده کنید. اگر تابع باید جزئیات پیاده‌سازی را پنهان کند — از some استفاده کنید. SwiftUI some View را انتخاب کرد دقیقاً به این دلیل که body باید در داخل منعطف اما در خارج پایدار باشد.

کلمه کلیدی some و کاربرد آن

some — کلمه کلیدی Swift است که در Swift 5.1 (SE-0244) معرفی شد. در موقعیت برگشتی برای اعلام opaque type و همچنین در پارامترها (SE-0341) و ویژگی‌ها استفاده می‌شود. some تضمین می‌کند که نوع مشخص پایدار و برای کامپایلر شناخته شده، اما از کد خارجی پنهان است.

some در پارامترهای تابع

از Swift 5.7، some نه تنها در موقعیت برگشتی، بلکه در پارامترها نیز قابل استفاده است. some Equatable در پارامتر به معنای «این تابع هر نوع Equatable را می‌پذیرد، اما همه فراخوانی‌های درون بدنه مشخص همان نوع را می‌بینند» است.

swift
func areEqual(_ a: some Equatable, _ b: some Equatable) -> Bool {
    // a و b — به طور پتانسیل انواع متفاوت، == مستقیماً کار نخواهد کرد
    return isEqual(a, b)
}

func isEqual<T: Equatable>(_ a: T, _ b: T) -> Bool {
    return a == b
}

استفاده از some در پارامترها نحو فشرده‌تری نسبت به <T> ارائه می‌دهد. به ویژه در پروتکل‌ها و طراحی پروتکل‌محور مفید است، جایی که هر استفاده از پروتکل به یک پارامتر generic جداگانه نیاز ندارد. کامپایلر در پشت صحنه some-پارامترها را به generic تبدیل می‌کند، بنابراین عملکرد یکسان است.

کلمه کلیدی any و انواع وجودی

any — کلمه کلیدی Swift 5.6+ برای اعلام صریح انواع وجودی (پروتکل به عنوان نوع) است. برخلاف some، any هویت نوع را پاک می‌کند: کامپایلر نمی‌داند چه نوع مشخصی پشت پروتکل پنهان شده است. این انعطاف‌پذیری می‌دهد (می‌توان انواع مختلف را در یک آرایه ذخیره کرد)، اما به قیمت عملکرد.

some vs any: تحلیل مقایسه‌ای

some — چندریختی ایستا: کامپایلر نوع مشخص را می‌داند، از توزیع مستقیم استفاده می‌کند و می‌تواند کد را درون‌خطی کند. any — چندریختی پویا: از جدول متدهای مجازی (existential container) استفاده می‌شود که غیرمستقیمی اضافه می‌کند.

swift
protocol Drawable {
    func draw()
}

// some: نوع ایستا شناخته شده است
func makeDrawable() -> some Drawable {
    return Circle() // نوع برگشتی واحد
}

// any: پویا، می‌تواند انواع مختلف را ذخیره کند
var shapes: [any Drawable] = [Circle(), Square()]
shapes.append(Triangle())

انتخاب بین some و any سازش بین عملکرد و انعطاف‌پذیری است. Some سریع‌تر است اما به یک پیاده‌سازی محدود می‌کند. Any انعطاف‌پذیرتر است (می‌توان انواع را مخلوط کرد) اما به دلیل توزیع پویا کندتر است. در SwiftUI برای body همیشه از some View استفاده می‌شود، زیرا body هر View یک نوع مشخص است.

Opaque Type در پروتکل‌های دارای associated types

Opaque Type مشکل اساسی Swift را حل می‌کند: پروتکل‌های دارای associated types (PAT) نمی‌توانند مستقیماً به عنوان نوع استفاده شوند. یک تابع نمی‌تواند به سادگی Collection برگرداند — کامپایلر نیاز به مشخص کردن Element دارد. some Collection این را حل می‌کند و associated type را پنهان می‌کند.

بازگرداندن PAT از طریق some

بدون opaque type برای بازگرداندن Collection باید از نوع مشخص (Array<Int>) یا پاک کردن نوع (AnyCollection<Int>) استفاده می‌شد. some Collection حد وسط طلایی می‌دهد: کامپایلر پیاده‌سازی مشخص را می‌داند، کد فراخواننده — نه.

swift
func makeReversedCollection<T>(
    of array: [T]
) -> some Collection {
    return array.reversed()
}

let result = makeReversedCollection(of: [1, 2, 3])
// result — ReversedCollection>, hidden from caller
for item in result {
    print(item)
}

result قابل پیمایش است، اما نمی‌توان مستقیماً به ویژگی‌های ReversedCollection دسترسی داشت. این از کپسوله‌سازی محافظت می‌کند: اگر بعداً reversed() با متد دیگری با پیاده‌سازی متفاوت جایگزین شود، کد فراخواننده خراب نمی‌شود. Opaque type آزادی تغییر پیاده‌سازی را بدون تغییر API می‌دهد.

مثال‌های عملی some View در SwiftUI

some View — معروف‌ترین کاربرد opaque type است. هر View در SwiftUI body را به عنوان some View اعلام می‌کند. این به این معنی است که body یک نوع View مشخص را برمی‌گرداند، اما برنامه‌نویس نیازی به فکر کردن درباره اینکه دقیقاً چه چیزی است — TupleView، Group، ModifiedContent یا هر نوع دیگر از فریم‌ورک — ندارد.

چگونه SwiftUI از some View استفاده می‌کند

بدون opaque type، body باید یک نوع مشخص را برمی‌گرداند، مثلاً ModifiedContent&lt;Button&lt;Text&gt;, Padding&gt;، که غیرعملی است. some View این پیچیدگی را پنهان می‌کند. کامپایلر نوع دقیق body را به طور خودکار هنگام کامپایل استخراج می‌کند.

swift
struct ContentView: View {
    var body: some View {
        VStack {
            Text("سلام")
                .font(.title)
            Button("مرا لمس کن") {
                print("لمس شد")
            }
        }
        .padding()
    }
}

کامپایلر body را به عنوان ModifiedContent&lt;VStack&lt;TupleView&lt;(Text, Button&lt;Text&gt;)&gt;&gt;, Padding&gt; استخراج می‌کند. برنامه‌نویس some View می‌بیند. اگر layout از VStack به HStack تغییر کند، کامپایلر به طور خودکار نوع را دوباره استخراج می‌کند — هیچ ویرایش دستی لازم نیست. این جادوی opaque type است: برنامه‌نویس روی منطق رابط تمرکز می‌کند، نه روی انواع ترکیب.

سوالات متداول

Opaque Type در Swift چیست؟

Opaque Type — نوعی است که با کلمه کلیدی some اعلام شده و پیاده‌سازی مشخص را از کد فراخواننده پنهان می‌کند. کامپایلر نوع دقیق را می‌داند، اما برنامه‌نویسی که از تابع استفاده می‌کند فقط پروتکل را می‌بیند.

تفاوت some و any در Swift چیست؟

some — opaque type با هویت ایستا: کامپایلر نوع مشخص را می‌داند. any — نوع وجودی با توزیع پویا: هویت نوع پاک شده است. Some کارآمدتر است، any انعطاف‌پذیرتر است.

چرا SwiftUI از some View استفاده می‌کند؟

some View نوع مشخص پیچیده body را که کامپایلر به طور خودکار استخراج می‌کند پنهان می‌کند. این برنامه‌نویس را از نیاز به نوشتن نوع دقیق متشکل از Generic-لفاف‌ها (VStack, Group, ModifiedContent) آزاد می‌کند.

آیا می‌توان از some در پارامترهای تابع استفاده کرد؟

بله، از Swift 5.7. some در پارامترها شکر نحوی بر روی پارامتر generic است. اعلام توابع را به ویژه هنگام کار با پروتکل‌ها ساده می‌کند، جایی که هر some-پارامتر به <T> جداگانه نیاز ندارد.

اگر از یک تابع some انواع مختلف برگردانده شود چه اتفاقی می‌افتد؟

کامپایلر خطا می‌دهد: opaque type نیاز دارد که همه شاخه‌های return همان نوع مشخص را برگردانند. این عمداً برای حفظ هویت نوع انجام شده است. اگر نیاز به بازگرداندن انواع مختلف دارید، از any استفاده کنید.

خلاصه

  • Opaque Type — نوع مشخص مقدار برگشتی را پنهان می‌کند و هویت آن را در سطح کامپایلر حفظ می‌کند
  • کلمه کلیدی some برای اعلام opaque type در موقعیت برگشتی و پارامترها استفاده می‌شود
  • Generic vs Opaque: caller نوع را برای generic انتخاب می‌کند، پیاده‌سازی — برای opaque
  • any — نوع وجودی با توزیع پویا، some — چندریختی ایستا
  • SwiftUI some View — کاربرد اصلی: نوع پیچیده body را از برنامه‌نویس پنهان می‌کند
  • Opaque type مشکل بازگرداندن پروتکل‌های دارای associated types (PAT) از توابع را حل می‌کند

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید