การเขียนฟังก์ชันที่ทนทานด้วย stop() และ warning()
ส่งสัญญาณเงื่อนไขแบบกำหนดเองจากภายในฟังก์ชันของคุณเอง
การเขียนฟังก์ชันที่ทนทานด้วย stop() และ warning() เป็นบทเรียน R Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน R Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดการตรวจสอบข้อมูลเข้าจึงสำคัญ
ฟังก์ชันเชิงป้องกันจะตรวจสอบข้อมูลเข้าและล้มเหลวอย่างชัดเจนพร้อมข้อผิดพลาดที่ให้ข้อมูล แทนที่จะสร้างผลลัพธ์ที่ผิดโดยไม่แจ้งให้ทราบ ฟังก์ชันที่ดักจับข้อมูลเข้าที่ไม่ถูกต้องตั้งแต่ขอบเขต จะดีบักได้ง่ายกว่าฟังก์ชันที่ปล่อยให้ข้อมูลขยะไหลผ่านกระบวนการต่อเนื่อง
# Without validation: wrong result, no error
bad_mean <- function(x) sum(x) / length(x)
bad_mean('hello') # no error, just NA
# With validation: clear error
good_mean <- function(x) {
if (!is.numeric(x)) stop('x must be numeric')
sum(x) / length(x)
}
tryCatch(good_mean('hello'), error = function(e) cat(e$message, '\n'))ข้อความข้อผิดพลาดที่ให้ข้อมูล
ข้อผิดพลาดทั่วไปอย่าง stop('bad input') ทำให้ดีบักได้ยาก ใช้ paste0() หรือ sprintf() ภายใน stop() เพื่อใส่ค่าจริงและประเภทที่คาดไว้ลงในข้อความ วิธีนี้ช่วยประหยัดเวลาเมื่อติดตามข้อผิดพลาดในกระบวนการต่อเนื่อง
check_numeric <- function(x, arg_name = 'x') {
if (!is.numeric(x)) {
stop(sprintf(
"'%s' must be numeric, but got class '%s'",
arg_name, class(x)
))
}
}
tryCatch(check_numeric('abc', 'score'),
error = function(e) cat(e$message, '\n'))การตรวจสอบความยาวและช่วงค่า
การตรวจสอบที่พบบ่อย ได้แก่ ตรวจสอบว่าเวกเตอร์ไม่ว่าง (length(x) == 0) ตรวจสอบว่าสเกลาร์อยู่ในช่วงที่กำหนด หรือ ตรวจสอบว่าตารางข้อมูลมีคอลัมน์ตามที่คาดไว้ การตรวจสอบแต่ละรายการควรมีข้อความข้อผิดพลาดที่ออกแบบให้เหมาะกับกรณีนั้น
validate_prob <- function(p) {
if (!is.numeric(p)) stop(paste0('p must be numeric, got: ', class(p)))
if (length(p) != 1) stop(paste0('p must be length 1, got: ', length(p)))
if (p < 0 || p > 1) stop(paste0('p must be in [0,1], got: ', p))
p
}
cat(validate_prob(0.7), '\n')
tryCatch(validate_prob(1.5), error = function(e) cat(e$message, '\n'))การใช้ warning() สำหรับปัญหาที่ไม่ร้ายแรง
ใช้ warning() เมื่อฟังก์ชันยังสามารถคืนผลลัพธ์ที่เหมาะสมได้ แต่ผู้เรียกควรทราบว่ามีสิ่งผิดปกติเกิดขึ้น เช่น การแปลงค่า การเติมค่าเริ่มต้น หรือการตรวจพบข้อมูลเข้าที่อยู่ใกล้ขอบเขต
clamp <- function(x, lo, hi) {
if (any(x < lo)) warning(paste0(sum(x < lo), ' value(s) below lo, clamped'))
if (any(x > hi)) warning(paste0(sum(x > hi), ' value(s) above hi, clamped'))
pmax(lo, pmin(hi, x))
}
result <- clamp(c(2, -5, 7, 100, 4), 0, 10)
cat('Result:', result, '\n')call. = FALSE ใน stop()
ตามค่าเริ่มต้น stop() จะเติม Error in funcname(...): ไว้หน้าข้อความ ส่ง call. = FALSE เพื่อระงับคำนำหน้านี้เมื่อบริบทของผู้เรียกชัดเจนอยู่แล้ว หรือเมื่อฟังก์ชันนั้นเป็นเครื่องมือที่ผู้ใช้เรียกโดยตรง
# With call. = TRUE (default): shows calling function
f1 <- function(x) stop('bad input')
tryCatch(f1(1), error = function(e) cat(conditionMessage(e), '\n'))
# With call. = FALSE: cleaner message
f2 <- function(x) stop('bad input', call. = FALSE)
tryCatch(f2(1), error = function(e) cat(conditionMessage(e), '\n'))คลาสเงื่อนไขแบบกำหนดเองสำหรับ stop()
สร้างคลาสข้อผิดพลาดแบบกำหนดเองด้วย structure() เพื่อให้ผู้เรียกดักจับเฉพาะข้อผิดพลาดจากฟังก์ชันของคุณ โดยไม่ดักจับข้อผิดพลาดทั้งหมด นี่คือแนวทางระดับมืออาชีพสำหรับการเขียนข้อผิดพลาดในระดับแพ็กเกจ
value_error <- function(msg, call = sys.call(-1)) {
structure(
class = c('value_error', 'error', 'condition'),
list(message = msg, call = call)
)
}
check_positive <- function(x) {
if (x <= 0) stop(value_error(paste0('Expected positive, got: ', x)))
x
}
tryCatch(check_positive(-3),
value_error = function(e) cat('ValueError:', e$message, '\n'),
error = function(e) cat('Other error:', e$message, '\n'))การตรวจสอบคอลัมน์ของตารางข้อมูล
เมื่อฟังก์ชันต้องการตารางข้อมูล ให้ตรวจสอบว่าคอลัมน์ที่จำเป็นมีอยู่ก่อนนำไปใช้ ใช้ %in% เพื่อตรวจสอบชื่อคอลัมน์ และใช้ setdiff() เพื่อรายงานว่าคอลัมน์ใดหายไป
require_cols <- function(df, cols) {
missing <- setdiff(cols, names(df))
if (length(missing) > 0) {
stop(paste0('Missing columns: ', paste(missing, collapse = ', ')))
}
invisible(df)
}
df <- data.frame(x = 1:3, y = 4:6)
tryCatch(
require_cols(df, c('x', 'z', 'w')),
error = function(e) cat(e$message, '\n')
)stopifnot() สำหรับการยืนยันแบบกระชับ
stopifnot(condition1, condition2, ...) จะโยนข้อผิดพลาดหากเงื่อนไขใด ๆ เป็น FALSE วิธีนี้เป็นแนวทางกระชับสำหรับยืนยันเงื่อนไขก่อนเริ่มทำงานที่ด้านบนของฟังก์ชัน โดยไม่ต้องเขียนบล็อก if (!...) stop(...) แยกกัน
compute_area <- function(width, height) {
stopifnot(
is.numeric(width),
is.numeric(height),
width > 0,
height > 0
)
width * height
}
cat(compute_area(5, 3), '\n')
tryCatch(compute_area(-1, 3), error = function(e) cat(e$message, '\n'))stopifnot() แบบตั้งชื่อเพื่อข้อความที่ดีขึ้น
ใน R 4.0+ นิพจน์ที่ตั้งชื่อภายใน stopifnot() จะแทนที่ข้อความที่สร้างขึ้นโดยอัตโนมัติด้วยคำอธิบายที่คุณกำหนดเอง ใช้ข้อความของนิพจน์เป็นชื่อเพื่อสร้างข้อความแจ้งความล้มเหลวที่ให้ข้อมูล
validate_age <- function(age) {
stopifnot(
'age must be numeric' = is.numeric(age),
'age must be positive' = age > 0,
'age must be under 150' = age < 150
)
invisible(age)
}
tryCatch(validate_age(-5), error = function(e) cat(e$message, '\n'))
tryCatch(validate_age('x'), error = function(e) cat(e$message, '\n'))การรวมการตรวจสอบกับตรรกะทางธุรกิจ
ฟังก์ชันที่มีโครงสร้างดีจะแยกการตรวจสอบออกจากตรรกะ ให้ตรวจสอบที่ด้านบน จากนั้นจึงดำเนินการ วิธีนี้ทำให้ฟังก์ชันอ่านง่ายขึ้น และทำให้แน่ใจว่าตรวจพบข้อผิดพลาดก่อนเริ่มการคำนวณ
discount_price <- function(price, pct) {
if (!is.numeric(price) || price <= 0)
stop(paste0('price must be positive numeric, got: ', price))
if (!is.numeric(pct) || pct < 0 || pct > 100)
stop(paste0('pct must be in [0,100], got: ', pct))
if (pct > 50) warning('discount > 50% is unusual')
price * (1 - pct / 100)
}
cat(discount_price(100, 20), '\n')
cat(suppressWarnings(discount_price(100, 60)), '\n')tryCatch ภายในฟังก์ชันอรรถประโยชน์
บางครั้งฟังก์ชันอรรถประโยชน์ควรจัดการข้อผิดพลาดภายในและคืนค่า fallback แทนการส่งต่อข้อผิดพลาด ให้ครอบตรรกะหลักด้วย tryCatch() และคืนค่าบ่งชี้ที่ตกลงกันไว้ เช่น NA หรือ NULL เมื่อทำงานล้มเหลว
safe_log <- function(x) {
tryCatch({
if (!is.numeric(x)) stop('not numeric')
if (x <= 0) stop('must be positive')
log(x)
}, error = function(e) {
warning(paste0('safe_log failed for x=', x, ': ', e$message))
NA_real_
})
}
results <- sapply(list(10, -1, 'a', 100), safe_log)
cat(results, '\n')ตรวจสอบอย่างรวดเร็ว
call. = FALSE ทำอะไรเมื่อส่งให้ stop()
ประเด็นสำคัญของฟังก์ชันที่ทนทาน
ประเด็นสำคัญสำหรับการเขียนฟังก์ชันที่ทนทาน:
- ตรวจสอบข้อมูลเข้าที่ด้านบน และล้มเหลวอย่างชัดเจนด้วยข้อความจาก
stop()ที่ให้ข้อมูล - ใส่ค่าจริงไว้ในข้อความข้อผิดพลาด:
paste0('Expected numeric, got: ', class(x)) - ใช้
warning()สำหรับปัญหาที่ไม่ร้ายแรงซึ่งยังดำเนินการคำนวณต่อได้ call. = FALSEระงับคำนำหน้าฟังก์ชันผู้เรียกในข้อความข้อผิดพลาด- ใช้
stopifnot()สำหรับการยืนยันแบบกระชับ และใช้รูปแบบตั้งชื่อสำหรับข้อความแบบกำหนดเอง (R 4.0+) - คลาสเงื่อนไขแบบกำหนดเองช่วยให้ผู้เรียกดักจับได้อย่างเลือกเจาะจง
robust_divide <- function(x, y) {
stopifnot('x must be numeric' = is.numeric(x),
'y must be numeric' = is.numeric(y))
if (y == 0) stop('Division by zero', call. = FALSE)
if (abs(y) < 1e-10) warning('y is very small; result may be inaccurate')
x / y
}
cat(robust_divide(10, 2), '\n')
tryCatch(robust_divide(10, 0), error = function(e) cat(e$message, '\n'))คำถามที่พบบ่อย
บทเรียน “การเขียนฟังก์ชันที่ทนทานด้วย stop() และ warning()” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การเขียนฟังก์ชันที่ทนทานด้วย stop() และ warning()” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส R Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การเขียนฟังก์ชันที่ทนทานด้วย stop() และ warning()”
ส่งสัญญาณเงื่อนไขแบบกำหนดเองจากภายในฟังก์ชันของคุณเอง คุณปฏิบัติ R Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน R Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน R Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การเขียนฟังก์ชันที่ทนทานด้วย stop() และ warning()” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน R Academy นี้ได้ไหม
ได้ บทเรียน R Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ข้อผิดพลาด คำเตือน และข้อความใน R
- tryCatch() สำหรับการกู้คืนจากข้อผิดพลาด
- withCallingHandlers() และการเริ่มทำงานใหม่
- การเขียนฟังก์ชันที่ทนทานด้วย stop() และ warning()