Either: bản chất, ứng dụng và nguyên lý hoạt động

Tác giả: IT Sectr Đã đăng: 2026-05-26 Thời gian đọc: 8 phút

Either là một kiểu hàm biểu diễn một giá trị trong hai biến thể khả dĩ: Left cho lỗi và Right cho thành công. Không giống như ngoại lệ, Either làm cho việc xử lý lỗi trở nên rõ ràng ở cấp độ kiểu và không yêu cầu khối try-catch. Theo Arrow, 2026, Either được sử dụng rộng rãi trong các dự án Kotlin để kết hợp các thao tác có thể thất bại mà không có tác dụng phụ.

Những điểm chính

  • Either là kiểu dữ liệu đại số biểu diễn hai biến thể loại trừ lẫn nhau: Left (lỗi) và Right (thành công).
  • Left theo truyền thống chứa thông tin lỗi, Right chứa giá trị chính xác.
  • Kiểu hóa rõ ràng — Either buộc phải xử lý cả hai biến thể tại thời điểm biên dịch, loại bỏ các lỗi không mong đợi.
  • Kết hợp — Either hỗ trợ map, flatMap và fold cho chuỗi biến đổi mà không cần kiểm tra lồng nhau.
  • Khác biệt với Result — Either có thể lưu trữ kiểu lỗi tùy ý, không chỉ Error hay Throwable.

Either là gì?

Either là một kiểu dữ liệu đại số, được vay mượn từ lập trình hàm, biểu diễn chính xác một trong hai kiểu khả dĩ. Trong bối cảnh xử lý lỗi, quy ước là: kiểu Left (Left) chứa mô tả vấn đề, trong khi kiểu Right (Right) chứa kết quả thành công.

Khái niệm Either bắt nguồn từ ngôn ngữ Haskell và phân loại kiểu Either a b, trong đó a là kiểu giá trị trái và b là kiểu giá trị phải. Trong phát triển di động, Either trở nên phổ biến nhờ thư viện Arrow cho Kotlin và các phương pháp hàm trong Swift.

Lợi thế chính của Either so với ngoại lệ là không có đường dẫn thực thi ẩn. Một hàm trả về Either khai báo rõ ràng trong chữ ký của nó rằng nó có thể thất bại. Trình biên dịch kiểm soát rằng cả hai biến thể đều được xử lý.

Không giống như ném ngoại lệ, Either duy trì tính minh bạch của luồng dữ liệu. Gọi một hàm trả về Either không yêu cầu try-catch ở phía người gọi — pattern-matching hoặc fold là đủ. Điều này đặc biệt quan trọng trong các kiến trúc có cách tiếp cận phản ứng, nơi mỗi nguồn dữ liệu trả về Either và chuỗi biến đổi được xây dựng qua map và flatMap.

Either hoạt động như thế nào: cấu trúc Left và Right

Either bao gồm hai kiểu con: LeftRight. Một thể hiện Either chỉ có thể là một trong hai vào mỗi thời điểm. Chữ ký điển hình trong Kotlin là Either<E, A>, trong đó E là kiểu lỗi và A là kiểu giá trị thành công.

Kiểu Left: vỏ chứa lỗi

Left biểu diễn trường hợp thất bại. Không giống ngoại lệ, Left không làm gián đoạn luồng thực thi — nó chỉ trả về một giá trị cần được xử lý. Kiểu lỗi có thể là bất kỳ: String, Int, một sealed class tùy chỉnh hoặc mô hình miền.

Kiểu Right: vỏ chứa thành công

Right chứa kết quả chính xác của thao tác. Tên gọi phản ánh sự đúng đắn — theo quy ước, Right có nghĩa là thành công. Các phép biến đổi như map và flatMap được áp dụng trên Right, cho phép xây dựng chuỗi tính toán mà không cần kiểm tra từng bước.

Kết hợp Either qua flatMap

flatMap là cơ chế chính để kết hợp Either. Nếu giá trị hiện tại là Right, flatMap áp dụng hàm được truyền vào và trả về một Either mới. Nếu là Left, flatMap bỏ qua phép biến đổi và chuyển tiếp lỗi. Hành vi này được gọi là đánh giá short-circuit.

Ngoài flatMap, Either còn hỗ trợ mapLeft để biến đổi lỗi, fold để xử lý cả hai biến thể tại một chỗ và getOrElse để trích xuất giá trị với giá trị mặc định. Các hàm này bao phủ mọi tình huống: từ trích xuất đơn giản đến kết hợp phức tạp với các lời gọi bất đồng bộ trong coroutine Kotlin hoặc Combine trong Swift.

kotlin
fun parseInt(input: String): Either<String, Int> =
    input.toIntOrNull()?.let { Right(it) }
    ?: Left("Không thể chuyển đổi: $input")

fun divide(a: Int, b: Int): Either<String, Int> =
    if (b == 0) Left("Chia cho không")
    else Right(a / b)

val result = parseInt("10")
    .flatMap { divide(it, 2) }

Either trong Kotlin: ứng dụng thực tế

Trong hệ sinh thái Kotlin, Either được triển khai trong thư viện Arrow. Thư viện chuẩn của Kotlin cung cấp Result, nhưng Either mang lại sự linh hoạt hơn: kiểu lỗi tùy ý, kết hợp qua flatMap và hỗ trợ các mẫu hàm.

Thư viện Arrow và Either

Arrow là thư viện hàm cho Kotlin bổ sung Either, Option, Validated và các kiểu khác. Arrow.Either là một sealed class với hai lớp con: ArrowCore.LeftArrowCore.Right. Thư viện cũng cung cấp các phần mở rộng tiện lợi: .getOrElse(), .fold(), .mapLeft().

Ví dụ: Either với yêu cầu mạng

Hãy xem xét một tình huống thực tế — một yêu cầu mạng trong ứng dụng Android với các lỗi có thể xảy ra: mất mạng, lỗi máy chủ, phản hồi không hợp lệ. Either cho phép kết hợp tất cả các biến thể thành một kiểu trả về duy nhất.

kotlin
sealed class NetworkError {
    data class NoConnection(val message: String): NetworkError()
    data class ServerError(val code: Int): NetworkError()
    data class ParseError(val detail: String): NetworkError()
}

suspend fun fetchUser(id: String): Either<NetworkError, User> {
    return try {
        val response = api.getUser(id)
        if (response.isSuccessful) {
            Right(response.body()!!)
        } else {
            Left(NetworkError.ServerError(response.code()))
        }
    } catch (e: IOException) {
        Left(NetworkError.NoConnection(e.message ?: ""))
    }
}

Either trong Swift: khác biệt với Result tiêu chuẩn

Trong Swift, từ phiên bản 5.0, kiểu Result tích hợp sẵn có sẵn, về khái niệm tương tự Either nhưng có hạn chế: lỗi phải tuân thủ giao thức Error và giá trị thành công phải là một kiểu duy nhất. Either trong Swift được triển khai thông qua enum với hai tham số generic.

Result tiêu chuẩn so với Either

Result<Success, Failure> là kiểu tích hợp của Swift, trong đó Failure: Error. Either không áp đặt ràng buộc về kiểu lỗi, cho phép lưu trữ String, cấu trúc tùy chỉnh hoặc thậm chí nhiều kiểu lỗi thông qua các enum lồng nhau.

swift
enum Either<E, A> {
    case left(E)
    case right(A)

    func map<B>(_ transform: (A) -> B) -> Either<E, B> {
        switch self {
        case .left(let e): return .left(e)
        case .right(let a): return .right(transform(a))
        }
    }
}

let result: Either<String, Int> = .right(42)
let mapped = result.map { $0 * 2 }

Khi nào sử dụng Either trong ứng dụng di động

Either là tối ưu cho các tình huống yêu cầu xử lý lỗi rõ ràng và an toàn kiểu mà không có ngoại lệ. Hãy xem xét các trường hợp sử dụng chính trong phát triển di động với Kotlin và Swift.

  • Yêu cầu mạng — mỗi yêu cầu có thể trả về lỗi kết nối, máy chủ hoặc phân tích cú pháp. Either tập hợp tất cả các biến thể thành một kiểu.
  • Xác thực biểu mẫu — Either với kiểu lỗi tùy chỉnh biểu diễn thuận tiện kết quả xác thực trường nhập: email hoặc mật khẩu không hợp lệ.
  • Kho dữ liệu — Either cho phép kết hợp kết quả từ các nguồn khác nhau (bộ nhớ đệm, DB, mạng) với một kiểu lỗi thống nhất.
  • Trình thông dịch lệnh — nếu ứng dụng phân tích đầu vào hoặc lệnh của người dùng, Either cung cấp cách an toàn kiểu để báo cáo lỗi.

Đừng sử dụng Either cho các thao tác đơn giản không có tác dụng phụ — giá trị trả về thông thường đáng tin cậy hơn và dễ đọc hơn. Either cũng là quá mức khi thất bại là một tình huống ngoại lệ chứ không phải kịch bản dự kiến.

Either cũng hiệu quả khi làm việc với coroutine trong Kotlin. Một hàm trả về Either có thể được gọi bên trong một coroutine với xử lý lỗi qua fold hoặc mapLeft mà không chặn luồng. Điều này đặc biệt hữu ích trong các ứng dụng Android với kiến trúc MVVM, nơi mỗi kho dữ liệu trả về Either và ViewModel biến đổi kết quả thành UiState.

Lỗi thường gặp khi làm việc với Either

Các nhà phát triển lần đầu làm quen với Either thường mắc phải những lỗi tương tự. Hãy xem xét những lỗi phổ biến nhất và cách tránh chúng.

  • Bỏ qua Left — gọi .getOrElse() với giá trị mặc định mà không phân tích nguyên nhân lỗi làm mất ý nghĩa sử dụng Either. Hãy xử lý lỗi một cách rõ ràng.
  • Kiểu lỗi toàn cục — sử dụng String hoặc Exception làm kiểu chung cho tất cả Either trong dự án làm giảm an toàn kiểu. Hãy tạo các sealed class miền.
  • Either lồng nhau — Either bên trong Right (Either<E, Either<E, A>>) làm phức tạp việc đọc. Sử dụng flatMap để làm phẳng.
  • Trộn lẫn với ngoại lệ — một hàm trả về Either nhưng bên trong ném ngoại lệ. Điều này mâu thuẫn với ý tưởng xử lý lỗi rõ ràng.

Câu hỏi thường gặp

Either khác Optional như thế nào?

Optional biểu diễn sự hiện diện hoặc vắng mặt của giá trị (Some/None), nhưng không cho biết nguyên nhân vắng mặt. Either cung cấp hai kiểu cụ thể — trái cho lỗi và phải cho thành công — cho phép truyền ngữ cảnh thất bại.

Có thể sử dụng Either trong Java không?

Trong Java không có Either tích hợp sẵn, nhưng các thư viện Vavr và functionaljava cung cấp triển khai. Trong phát triển Android, Either từ Vavr là một lựa chọn thay thế phổ biến cho phong cách hàm với lambda.

Khi nào nên dùng sealed class thay vì Either?

Sealed class trong Kotlin tiện hơn khi có nhiều hơn hai biến thể hoặc chúng có cấu trúc khác nhau. Đối với kết quả nhị phân (lỗi/thành công), Either nhỏ gọn hơn và cung cấp các bộ kết hợp hàm có sẵn.

Either có hỗ trợ đa luồng không?

Either là bất biến và an toàn luồng theo mặc định. Trong Kotlin với coroutine, Either kết hợp hoàn hảo: flatMap hoạt động trong phạm vi coroutine và xử lý lỗi không yêu cầu khóa.

Có nên sử dụng Either cho mọi hàm trong dự án không?

Không. Either phù hợp cho các thao tác có lỗi dự kiến (mạng, xác thực, logic nghiệp vụ). Đối với các getter đơn giản và tính toán không có tác dụng phụ, kiểu thông thường dễ đọc hơn và không thêm độ phức tạp không cần thiết.

Tổng kết

  • Either là kiểu hàm biểu diễn hai biến thể: Left (lỗi) và Right (thành công), làm cho việc xử lý lỗi trở nên rõ ràng ở cấp kiểu.
  • Left có thể chứa kiểu lỗi tùy ý — từ String đến sealed class miền, không giống như Result tiêu chuẩn.
  • flatMap cho phép kết hợp Either mà không cần kiểm tra lồng nhau: lỗi tự động lan truyền qua toàn bộ chuỗi.
  • Arrow là thư viện Either chính cho Kotlin với hỗ trợ coroutine tích hợp và các phần mở rộng.
  • Swift sử dụng Result tích hợp, nhưng Either có thể được triển khai qua enum với hai tham số generic để linh hoạt tối đa.
  • Sử dụng Either cho yêu cầu mạng, xác thực biểu mẫu và kho dữ liệu — các tình huống có lỗi dự kiến.
  • Tránh kiểu lỗi toàn cục, bỏ qua Left và Either lồng nhau — điều này làm giảm lợi ích của an toàn kiểu.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm