0Pricing
R Academy · Aula

Escrevendo funções robustas com stop() e warning()

Gere condições personalizadas dentro de suas próprias funções.

Escrevendo funções robustas com stop() e warning() é uma aula grátis de R Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de R Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de R Academy inclui 4 aulas no total.

Por que a validação de entradas é importante

Funções defensivas verificam suas entradas e falham de forma explícita, com erros informativos, em vez de produzir resultados incorretos silenciosamente. Uma função que captura entradas inválidas na fronteira é muito mais fácil de depurar do que uma que propaga dados inválidos por um fluxo de processamento.

# 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'))

Mensagens de erro informativas

Erros genéricos como stop('bad input') são frustrantes de depurar. Use paste0() ou sprintf() dentro de stop() para incluir o valor real e o tipo esperado na mensagem. Isso economiza tempo ao rastrear erros em fluxos de processamento.

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'))

Validando comprimento e intervalo

Validações comuns: verificar se um vetor não está vazio (length(x) == 0), se um escalar está dentro de um intervalo ou se um quadro de dados tem as colunas esperadas. Cada verificação deve ter sua própria mensagem de erro específica.

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'))

Usando warning() para problemas não fatais

Use warning() quando a função ainda puder retornar um resultado sensato, mas o chamador precisar saber que algo incomum aconteceu — como converter um valor, atribuir um padrão ou detectar uma entrada limítrofe.

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 em stop()

Por padrão, stop() acrescenta Error in funcname(...): ao início da mensagem. Passe call. = FALSE para suprimir esse prefixo quando o contexto da chamada for óbvio ou quando a função for um utilitário voltado para usuários.

# 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'))

Classes de condição personalizadas para stop()

Crie uma classe de erro personalizada usando structure() para que os chamadores possam capturar apenas os erros da sua função, sem capturar todos os erros. Essa é a forma profissional de escrever erros no nível de um pacote.

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'))

Verificando colunas de quadros de dados

Quando uma função espera um quadro de dados, valide se as colunas necessárias existem antes de usá-las. Use %in% para verificar os nomes das colunas e setdiff() para informar quais colunas estão ausentes.

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() para asserções concisas

stopifnot(condition1, condition2, ...) lança um erro se qualquer condição for FALSE. É uma forma concisa de afirmar pré-condições no início de uma função, sem escrever blocos separados de 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() nomeado para mensagens melhores

No R 4.0+, expressões nomeadas em stopifnot() substituem a mensagem gerada automaticamente pela sua descrição personalizada. Use o texto da expressão como nome para produzir falhas informativas.

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'))

Combinando validação e lógica de negócio

Uma função bem estruturada separa a validação da lógica. Valide no início e depois execute a operação. Isso facilita a leitura da função e garante que os erros sejam detectados antes do início de qualquer cálculo.

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 dentro de funções utilitárias

Às vezes, uma função utilitária deve tratar os erros internamente e retornar um valor alternativo em vez de propagá-los. Envolva a lógica principal em tryCatch() e retorne um valor sentinela definido, como NA ou NULL, em caso de falha.

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')

Verificação rápida

O que call. = FALSE faz quando é passado para stop()?

Funções robustas: principais conclusões

Principais conclusões sobre como escrever funções robustas:

  • Valide as entradas no início; falhe de forma explícita com mensagens informativas de stop()
  • Inclua o valor real nas mensagens de erro: paste0('Expected numeric, got: ', class(x))
  • Use warning() para problemas não fatais nos quais o cálculo pode continuar
  • call. = FALSE suprime o prefixo da função chamadora nas mensagens de erro
  • Use stopifnot() para asserções concisas e a forma nomeada para mensagens personalizadas (R 4.0+)
  • Classes de condição personalizadas permitem a captura seletiva pelos chamadores
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'))

Perguntas Frequentes

A aula “Escrevendo funções robustas com stop() e warning()” é grátis?

Sim — o texto completo de “Escrevendo funções robustas com stop() e warning()” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de R Academy, atualize para CoddyKit PRO. O curso de R Academy inclui 4 aulas no total.

O que vou aprender em “Escrevendo funções robustas com stop() e warning()”?

Gere condições personalizadas dentro de suas próprias funções. Você pratica R Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar R Academy?

Nenhuma experiência prévia é necessária. R Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Escrevendo funções robustas com stop() e warning()”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de R Academy?

Sim. Cada aula de R Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Erros, avisos e mensagens em R
  2. tryCatch() para recuperação de erros
  3. withCallingHandlers() e reinicializações
  4. Escrevendo funções robustas com stop() e warning()
← Voltar para R Academy