Opaque là gì?

Tháng 2 10, 2025

Opaque Type trong Swift, còn được gọi là Opaque Return Type, là một khái niệm ra đời từ Swift 5.1. Opaque Type giúp đơn giản hóa việc sử dụng Protocol và Generic, đặc biệt là với các Protocol có Associated Type. Bài viết này sẽ giải thích Opaque Là Gì và cách sử dụng nó.

Vấn đề khi sử dụng Protocol và Generic

Khi một function trả về một Protocol có Associated Type, việc xác định kiểu dữ liệu cụ thể cho giá trị trả về gặp khó khăn. Ví dụ:

protocol P {
    associatedtype Value
    var value: Value { get } 
    init(value: Value) 
}

struct S1 : P { 
    var value: Int 
} 
struct S2: P { 
    var value: String 
}

// Lỗi: Không thể suy ra kiểu trả về
// func foo() -> P { return S1() } 

Sử dụng Generic cũng có hạn chế vì cần chỉ rõ kiểu dữ liệu cho tham số hoặc giá trị trả về của function:

func foo<T: P>(value: T.Value) -> T { return T(value: value) }
let s1: S1 = foo(value: 10) 
let s2: S2 = foo(value: "ahihi")

Giải pháp với Opaque Type

Opaque Type, được khai báo bằng từ khóa some, cho phép function trả về một kiểu dữ liệu “ẩn” mà chỉ cần tuân thủ Protocol, không cần xác định cụ thể.

func foo() -> some P { return S1(value: 11) }

Trong ví dụ trên, some P đại diện cho một kiểu dữ liệu cụ thể nào đó thỏa mãn Protocol P, trình biên dịch sẽ tự động suy luận.

Tuy nhiên, Opaque Type chỉ cho phép trả về một kiểu dữ liệu duy nhất trong cùng một function:

// Lỗi: Không thể trả về nhiều kiểu dữ liệu khác nhau
// func bar(_ x: Int) -> some P {
//     if x > 10 { return S1(value: 12) } 
//     else { return S2(value: "ahihi") } 
// }

Opaque Type và PATs (Protocols with Associated Types)

Opaque Type đặc biệt hữu ích khi làm việc với PATs. Nó cho phép sử dụng PATs làm kiểu trả về mà không cần biết kiểu dữ liệu cụ thể, giúp code linh hoạt hơn và không bị ràng buộc bởi phiên bản thư viện.

func giveMeACollection() -> some Collection { return [1, 2, 3] }
let collection = giveMeACollection()
print(collection.count) // 3

Opaque Type và kiểu xác định

Khi một function với Opaque Type trả về một kiểu cụ thể, trình biên dịch đảm bảo rằng các lần gọi đến function đó luôn trả về cùng một kiểu.

func fooo() -> some Equatable { return 5 }
let f1 = fooo() 
let f2 = fooo()
print(f1 == f2) // true

Tuy nhiên, điều này không đúng với PATs. Mỗi function với Opaque Type và PATs sẽ trả về một kiểu dữ liệu riêng biệt, ngay cả khi chúng cùng tuân thủ một Protocol.

Opaque Type và Generic Placeholders

Kết hợp Opaque Type với Generic Placeholders cho phép tạo ra các function vừa đa năng với nhiều kiểu dữ liệu, vừa không cần trả về kiểu cụ thể.

Tại sao nên sử dụng Opaque Type?

Opaque Type mang lại sự linh hoạt khi làm việc với Protocol, đặc biệt là PATs. Nó giúp tránh việc phải xác định kiểu dữ liệu cụ thể, giảm sự ràng buộc với phiên bản thư viện và tăng tính tái sử dụng của code.

Opaque Type trong SwiftUI

Opaque Type được sử dụng rộng rãi trong SwiftUI. Thuộc tính body của View Protocol có kiểu some View, cho phép trả về bất kỳ kiểu dữ liệu nào tuân thủ View Protocol, giúp đơn giản hóa việc xây dựng giao diện người dùng. Việc sử dụng some View giúp tránh kiểu dữ liệu phức tạp khi View có nhiều cấp lồng nhau.

Leave A Comment

Create your account