Either<L, R>: การจัดการข้อผิดพลาดตามชนิดโดยไม่ใช้ Exception
ใช้ Either เพื่อแทนผลสำเร็จและความล้มเหลวโดยไม่ต้องโยนข้อยกเว้น
Either<L, R>: การจัดการข้อผิดพลาดตามชนิดโดยไม่ใช้ Exception เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
ปัญหาของการใช้ข้อยกเว้นกับตรรกะทางธุรกิจ
ข้อยกเว้นออกแบบมาสำหรับความล้มเหลวที่ไม่คาดคิด เช่น ตัวชี้ค่าว่างหรือข้อผิดพลาด IO การใช้ข้อยกเว้นเพื่อสื่อถึงความล้มเหลวทางธุรกิจที่คาดไว้ เช่น การตรวจสอบไม่ผ่านหรือ "ไม่พบ" ทำให้ลำดับการทำงานมองไม่เห็น บังคับให้เขียน try/catch ในทุกจุดที่เรียกใช้ และซ่อนข้อผิดพลาดไว้จากลายเซ็นของฟังก์ชัน
Either<L, R> คืออะไร
Either เป็นชนิดผลรวมที่มีได้สองกรณี: โดยทั่วไป Left(value: L) ใช้เก็บข้อผิดพลาด และ Right(value: R) ใช้เก็บค่าที่สำเร็จ ฟังก์ชันที่คืนค่าเป็น Either จะระบุความเป็นไปได้ที่จะล้มเหลวไว้อย่างชัดเจนในลายเซ็นของฟังก์ชัน
Either ของ Arrow
เพิ่ม Arrow ลงในโครงการเพื่อใช้งาน Either และชุดระบบนิเวศของตัวดำเนินการทั้งหมด:
// build.gradle.kts
implementation("io.arrow-kt:arrow-core:1.2.4")
// Usage
import arrow.core.Either
import arrow.core.left
import arrow.core.rightการคืนค่า Either จากฟังก์ชัน
คืนค่า value.right() เมื่อสำเร็จ และ error.left() เมื่อล้มเหลว ผู้เรียกต้องจัดการทั้งสองแขนง:
sealed class UserError { object NotFound : UserError(); data class InvalidEmail(val msg: String) : UserError() }
fun findUser(id: Long): Either<UserError, User> =
if (id <= 0) UserError.NotFound.left()
else User(id, "Alice").right()การใช้ Either ด้วย fold
ใช้ fold(ifLeft, ifRight) เพื่อจัดการทั้งสองกรณีภายในนิพจน์เดียว:
val result = findUser(1L)
val message = result.fold(
ifLeft = { error -> "Error: $error" },
ifRight = { user -> "Found: ${user.name}" }
)
println(message)การแปลงค่า Right ด้วย map
map { } จะแปลงค่า Right โดยไม่แตะต้อง Left ทำให้ Either เป็นฟังก์เตอร์ ซึ่งช่วยให้คุณเชื่อมการแปลงค่าอย่างปลอดภัยได้:
val nameResult: Either<UserError, String> = findUser(1L).map { it.name }การเชื่อมการทำงานด้วย flatMap
flatMap { } ใช้เชื่อมการคำนวณที่คืนค่าเป็น Either เช่นกัน หากขั้นตอนใดคืนค่า Left การเชื่อมทั้งหมดจะหยุดทันที และข้อผิดพลาดจะถูกส่งต่อโดยไม่เรียกใช้ขั้นตอนถัดไป:
fun validateEmail(email: String): Either<UserError, String> =
if (email.contains("@")) email.right()
else UserError.InvalidEmail("bad format").left()
fun createUser(email: String): Either<UserError, User> =
validateEmail(email).flatMap { validEmail ->
User(1L, validEmail).right()
}Either.catch สำหรับการห่อข้อยกเว้น
Either.catch { } จะเรียกใช้บล็อกคำสั่งและห่อข้อยกเว้นใด ๆ เป็น Left ใช้ที่ขอบเขตระหว่างโค้ดเดิมที่โยนข้อยกเว้นกับโดเมนที่ใช้ Either:
val result: Either<Throwable, User> = Either.catch {
userRepository.findOrThrow(id)
}การกู้คืนด้วย getOrElse และ orElse
getOrElse { default } ดึงค่า Right หรือคืนค่าเริ่มต้น หากไม่มีค่า orElse { alternativeEither } จะแทนที่ Left ด้วยการคำนวณอื่น:
val user: User = findUser(0L).getOrElse { User(-1L, "Guest") }
val user2: Either<UserError, User> = findUser(0L).orElse { User(99L, "Default").right() }การจับคู่รูปแบบด้วย when
ใช้ when กับคลาสลักษณะเดียวกับ Either ที่เป็น sealed หรือใช้กับ Either โดยตรงผ่าน is Either.Left / Either.Right เพื่อจัดการทุกกรณีอย่างครบถ้วน:
when (val r = findUser(1L)) {
is Either.Left -> println("Error: ${r.value}")
is Either.Right -> println("User: ${r.value.name}")
}Either ในชั้นบริการ
ให้ฟังก์ชันของคลังข้อมูลและบริการคืนค่าเป็น Either จากนั้นแปลงค่าเป็นการตอบกลับ HTTP ที่ระดับเส้นทางของ Ktor เพื่อให้ตรรกะทางธุรกิจไม่ขึ้นกับรายละเอียดของเฟรมเวิร์ก:
get("/users/{id}") {
val id = call.parameters["id"]?.toLongOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest)
userService.findById(id).fold(
ifLeft = { call.respond(HttpStatusCode.NotFound) },
ifRight = { call.respond(it) }
)
}ตรวจสอบความเข้าใจ
flatMap { } ทำอะไรกับค่า Either.Left
สรุป: Either<L, R>
ประเด็นสำคัญ:
Eitherทำให้เส้นทางความล้มเหลวปรากฏอย่างชัดเจนในลายเซ็นของฟังก์ชันRight= สำเร็จ;Left= ล้มเหลว (ตามธรรมเนียม)map { }— แปลงค่าสำเร็จ;flatMap { }— เชื่อมการคำนวณที่อาจล้มเหลวfold(ifLeft, ifRight)— จัดการทั้งสองกรณีในนิพจน์เดียวEither.catch { }— ห่อโค้ดที่โยนข้อยกเว้นไว้ที่ขอบเขต
คำถามที่พบบ่อย
บทเรียน “Either<L, R>: การจัดการข้อผิดพลาดตามชนิดโดยไม่ใช้ Exception” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “Either<L, R>: การจัดการข้อผิดพลาดตามชนิดโดยไม่ใช้ Exception” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “Either<L, R>: การจัดการข้อผิดพลาดตามชนิดโดยไม่ใช้ Exception”
ใช้ Either เพื่อแทนผลสำเร็จและความล้มเหลวโดยไม่ต้องโยนข้อยกเว้น คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “Either<L, R>: การจัดการข้อผิดพลาดตามชนิดโดยไม่ใช้ Exception” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม
ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- Either : การจัดการข้อผิดพลาดตามชนิดโดยไม่ใช้ Exception
- Arrow Raise DSL: การประกอบข้อผิดพลาดแบบมีชนิด
- Option และ Nullable: ควรใช้แต่ละแบบเมื่อใด
- การสร้างแบบจำลองโดเมนเชิงฟังก์ชันด้วยชนิดหลักของ Arrow