Pular para o conteúdo

Erro E0603 do Rust: function, struct or module is private (item privado)

O E0603 é uma boa notícia disfarçada: o Rust encontrou a função, a struct ou o módulo que você pediu. Ele só não tem permissão para entregar, porque o item é privado. Tudo num módulo Rust é privado até você dizer o contrário, então esse erro aparece para quase todo mundo na primeira vez que divide o código em módulos. A correção costuma ser uma palavra só: pub. Para os outros erros desta série, veja Erros do compilador Rust.

error[E0603]: function `apply_discount` is private
--> src/main.rs:8:26
|
8 | let total = billing::apply_discount(200); // ❌ privada
| ^^^^^^^^^^^^^^ private function
|
note: the function `apply_discount` is defined here
--> src/main.rs:2:5
|
2 | fn apply_discount(price: u32) -> u32 { // sem `pub`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Em português: “a função apply_discount é privada”. A nota mostra onde a função foi definida.

Este é o programa que gera o erro:

mod billing {
fn apply_discount(price: u32) -> u32 { // sem `pub`
price * 90 / 100
}
}
fn main() {
let total = billing::apply_discount(200); // ❌ privada
println!("Total: {total}");
}

A primeira linha diz o tipo de item, então o mesmo erro aparece em algumas variações:

O que a primeira linha diz O que costuma ter dado errado Correção
function `apply_discount` is private o fn não tem pub Correção 1 ou 2
struct `Order` is private a struct não tem pub Correção 1
module `prices` is private um mod no caminho não tem pub Correção 1 ou 3
function import `price_of` is private você chegou ao item por um use simples dentro de outro módulo Correção 3
tuple struct constructor `Percent` is private a struct é pub, mas os campos dela não são Correção 4

Leia as duas setas. A primeira (linha 8) é onde você usa o item. A seta do note: (linha 2) é onde o item é definido. O Rust está dizendo: “estou vendo apply_discount ali, mas ela nunca foi marcada como compartilhada, então o código fora de billing não pode chamá-la”.

O arquivo não importa. Se billing estiver em src/billing.rs, você recebe o mesmo erro, e o note: simplesmente aponta para src/billing.rs:1:1.

Pense num prédio de escritórios. Cada módulo é uma sala com porta. Um item privado é uma ferramenta que fica na sala dela: quem está dentro da sala (e nas salas menores dentro dela) pode usar, mas ninguém do corredor pode. O pub coloca a ferramenta numa prateleira no corredor.

O Rust deixa tudo privado por padrão: funções, structs, campos de structs, módulos e até imports com use. Você escolhe compartilhar com pub. A lição de Módulos mostra isso desde o começo.

O motivo é a segurança do você do futuro. Tudo o que é pub vira uma promessa: outro código pode depender daquilo, então mudar pode quebrar esse código. Itens privados podem ser alterados, renomeados ou apagados à vontade, e o compilador garante que ninguém de fora depende deles. Funções auxiliares continuam auxiliares, e uma struct pode proteger as próprias regras (como “o saldo nunca é negativo”), porque ninguém mais mexe nos campos dela diretamente.

Mais um detalhe: a privacidade é verificada em cada passo de um caminho. shop::prices::price_of só funciona se prices estiver visível para você e price_of também. Um pub fn dentro de um módulo privado continua fora de alcance.

Correção 1: Coloque pub no item (e em cada módulo do caminho)

Seção intitulada “Correção 1: Coloque pub no item (e em cada módulo do caminho)”

Escolha esta quando o item foi feito para ser usado de fora do módulo. Na maioria das vezes, é a correção certa:

mod billing {
pub fn apply_discount(price: u32) -> u32 {
price * 90 / 100
}
}
fn main() {
let total = billing::apply_discount(200);
println!("Total: {total}");
}

Saída:

Total: 180
▶ Experimente você mesmo

Se o erro disser module `prices` is private (o módulo prices é privado), o pub que falta está no módulo: escreva pub mod prices { ... }. O rustc também indica esse caso com um segundo rótulo, function `price_of` is not publicly re-exported (a função price_of não é reexportada publicamente). Com um arquivo separado, o pub vai na linha da declaração: pub mod prices;.

Numa struct, pub struct Order torna o tipo público, mas cada campo ainda precisa do próprio pub se o código de fora tiver que ler ou alterar esse campo. Mais sobre isso na Correção 4.

Correção 2: Use pub(crate) ou pub(super) para “só o meu código”

Seção intitulada “Correção 2: Use pub(crate) ou pub(super) para “só o meu código””

Escolha esta quando o item deve ser compartilhado, mas não com o mundo inteiro. O pub tem alguns níveis, do menor para o maior:

Você escreve Quem pode usar o item
nada (privado) o próprio módulo e os módulos dentro dele
pub(super) também o módulo pai
pub(crate) qualquer código deste crate
pub todo mundo, incluindo outros crates que dependem do seu

Num programa (um binário), pub(crate) e pub se comportam quase igual. A diferença importa numa biblioteca: pub(crate) deixa os seus módulos compartilharem uma função auxiliar sem que ela vire parte da API pública da biblioteca.

mod shop {
// Qualquer código deste crate pode chamar esta função.
pub(crate) fn store_name() -> &'static str {
"Ferris Fruits"
}
pub mod receipt {
// Só o módulo pai, `shop`, pode chamar esta função auxiliar.
pub(super) fn line(item: &str, price: u32) -> String {
format!("{item}: {price}")
}
}
pub fn print_receipt(items: &[(&str, u32)]) {
println!("== {} ==", store_name());
for (item, price) in items {
println!("{}", receipt::line(item, *price));
}
}
}
fn main() {
println!("Boas-vindas à {}", shop::store_name());
shop::print_receipt(&[("apple", 3), ("pear", 5)]);
// shop::receipt::line("apple", 3); // ❌ E0603: `line` é só para `shop`
}

Saída:

Boas-vindas à Ferris Fruits
== Ferris Fruits ==
apple: 3
pear: 5
▶ Experimente você mesmo

Tire o // da frente da última linha e você recebe function `line` is private (a função line é privada), mesmo com o pub(super). main não é o pai de receipt, então a porta continua fechada.

Escolha esta quando o módulo interno é um detalhe de implementação, mas um item dentro dele deve ser fácil de alcançar. Mantenha o módulo privado e coloque o item num caminho público mais curto:

mod shop {
mod prices {
// continua privado: como os preços são guardados é assunto do shop
pub fn price_of(item: &str) -> u32 {
if item == "apple" { 3 } else { 5 }
}
}
pub use prices::price_of; // agora dá para chegar como shop::price_of
}
fn main() {
println!("Maçãs custam {}", shop::price_of("apple"));
println!("Peras custam {}", shop::price_of("pear"));
}

Saída:

Maçãs custam 3
Peras custam 5
▶ Experimente você mesmo

Esta também é a correção para function import `price_of` is private (o import da função price_of é privado). Um use prices::price_of; simples dentro de shop é um atalho só para o shop; como todo o resto, um use é privado. O pub use transforma o atalho numa porta pública. Crates grandes fazem isso o tempo todo, e é por isso que você pode escrever serde::Serialize sem saber em qual módulo interno ele mora.

Correção 4: Crie um pub fn new em vez de tornar os campos públicos

Seção intitulada “Correção 4: Crie um pub fn new em vez de tornar os campos públicos”

Escolha esta quando o erro é sobre os campos de uma struct ou sobre o construtor dela. Aqui a struct é pub, mas o campo não é:

mod billing {
pub struct Percent(u8);
}
fn main() {
let discount = billing::Percent(150); // ❌ construtor privado
}
error[E0603]: tuple struct constructor `Percent` is private
--> src/main.rs:6:29
|
2 | pub struct Percent(u8);
| -- a constructor is private if any of the fields is private
...
6 | let discount = billing::Percent(150); // ❌ construtor privado
| ^^^^^^^ private tuple struct constructor
|
help: consider making the field publicly accessible
|
2 | pub struct Percent(pub u8);
| +++

O compilador explica que um construtor é privado se qualquer um dos campos for privado e sugere tornar o campo público. O rustc propõe pub u8, e para um tipo que só guarda dados isso não tem problema. Mas olhe o valor: 150 por cento! Muitas vezes o campo privado é justamente o objetivo. O módulo quer verificar o valor antes de um Percent existir. Dê a ele um construtor público que faz essa verificação:

mod billing {
pub struct Percent(u8);
impl Percent {
pub fn new(value: u8) -> Option<Percent> {
if value <= 100 { Some(Percent(value)) } else { None }
}
pub fn apply(&self, price: u32) -> u32 {
price * (100 - self.0 as u32) / 100
}
}
}
fn main() {
let ten = billing::Percent::new(10).unwrap();
println!("200 com 10% de desconto: {}", ten.apply(200));
println!("150% é permitido? {}", billing::Percent::new(150).is_some());
}

Saída:

200 com 10% de desconto: 180
150% é permitido? false
▶ Experimente você mesmo

Agora todo Percent do programa inteiro está garantidamente entre 0 e 100, e apply nunca dá underflow (resultado abaixo de zero). Lembre que o próprio new também precisa de pub; um método privado gera outro erro, o E0624 (associated function `new` is private). Veja Structs para saber mais sobre construtores.

Um pacote com main.rs e lib.rs. São dois crates separados, e o main.rs usa a biblioteca de fora. Se lib.rs diz mod inventory;, então use shop::inventory::count_items; no main.rs falha:

error[E0603]: module `inventory` is private
--> src/main.rs:1:11
|
1 | use shop::inventory::count_items;
| ^^^^^^^^^ private module

O compilador avisa que o módulo inventory é privado. Correção: escreva pub mod inventory; no lib.rs e pub fn count_items no módulo. Cuidado: pub(crate) não basta aqui. Para a biblioteca, o main.rs é outro crate, então um pub(crate) fn continua dando function `count_items` is private. Veja Cargo e crates.

Campos privados de structs. Eles têm códigos de erro próprios. Criar uma struct com um campo privado dá E0451, e ler esse campo dá E0616:

error[E0451]: field `balance` of struct `Account` is private
error[E0616]: field `balance` of struct `Account` is private

Nos dois casos, o campo balance da struct Account é privado. Correção: a mesma escolha da Correção 4. Coloque pub no campo se qualquer um pode alterá-lo, ou mantenha-o privado e acrescente pub fn new(...) mais um getter como pub fn balance(&self) -> u64.

Uma função que você achou no código-fonte de um crate. Você leu um crate no GitHub, achou a função auxiliar perfeita e recebe o E0603 ao chamá-la. Se os autores do crate não a fizeram pub, você não pode usá-la, e eles podem mudá-la a qualquer momento. Procure uma forma pública de fazer a mesma coisa na página do crate no docs.rs; só itens pub aparecem lá.

  • E0432: unresolved import (import não resolvido). O item nem foi encontrado. No E0603 ele foi encontrado, mas é privado.
  • E0433: failed to resolve (falha ao resolver), um caminho no seu código que não leva a lugar nenhum.
  • E0451 e E0616: um campo de struct é privado (ao criar a struct ou ao ler o campo).
  • E0624: um método ou uma função associada (como new) é privado.
  • Todos os erros do compilador: a lista completa de páginas de erro.

Teste o que aprendeu

1. mod shop { mod prices { pub fn price_of() {} } } e main chama shop::prices::price_of(). Qual erro aparece?

2. Uma função auxiliar em src/lib.rs está marcada como pub(crate). O src/main.rs do mesmo pacote pode chamá-la?

3. Uma pub struct Email(String); mantém o campo privado de propósito. Qual é o jeito amigável de deixar outros módulos criarem uma?

Pontuação: 0 / 3