Clique sobre os tópicos listados abaixo para navegar até o conteúdo desejado.

  1. Função interna
  2. Array de funções
  3. Retornando função
  4. Ponteiro para função
  5. Recursão

Assim como em várias linguagens, Rust possui suporte a criação de funções e procedimentos com o objetivo de dividir, organizar e reutilizar trechos de código em nossas aplicações. Nesta parte vamos aprender a declarar uma função, declarar uma função com parâmetros e também sobre passagem por valor referências além de outros assuntos.

Os conceitos básicos sobre função e procedimento foram visto em Portugol: Funções e Portugol: Procedimentos da linguagem Portugol. A leitura é recomenda.

Para declararmos funções na linguagem Rust é feita como na sintaxe apresentada abaixo:

Sintaxe:
fn nome_funcao() {
   //corpo
}
Onde
fn: palavra reservada de identificação
nome_funcao: nome da função que desejamos declarar
Exemplo 1
fn funcao() {
    println!("corpo da funcao aqui");
}

Para invocar um procedimento, utilizamo seu próprio nome no local desejado.

Sintaxe:
fn nome_funcao() {
   //corpo
}
Onde
fn: palavra reservada para identificação de um função
nome_funcao: nome da função que desejamos declarar
Exemplo 1
fn funcao() {
    println!("corpo da funcao aqui");
}
Sintaxe:
minha_funcao()
Exemplo 2
fn funcao() {
    println!("corpo da funcao aqui");
}
Saída
corpo da função aqui

As funções podem ser declarados antes ou depois da função main, levando em consideração que possuímos apenas um arquivo .rs contendo um função main.

Exemplo 3: depois da main
fn main()
{
 funcao();
}

fn funcao() 
{
    println!("funcao");
}
Saída
funcao
Exemplo 4: antes da main
fn funcao(param1: i8, param2:f32) 
{
    println!("param1:{} param2:{}",param1,param2);
}

fn main()
{
 funcao(1,1.99);
}
Saída
funcao

Diferente de linguagens como C e C++ não precisamos declarar protótipos antes da função main.

Em uma futura seção, Módulo, vamos aprender a separa os nossos programas em arquivos .rsgo para melhor organização.

A declaração de parâmetros em funções é semelhante a outras linguagens estilo-C e que respeita as mesmas regras que vistas para variáveis. Abaixo, é mostrada a sintaxe para declaração de parâmetros:

Sintaxe
fn nome_funcao( nome_param1:tipo_dado, nome_param2:tipo_dado2, nome_paramN:tipo_dadoN)
{
  //corpo
}
Onde
nome_funcao: nome da função que desejamos criar
param1..N: nome do parâmetro
tipo_dado1..N: tipo de dado do parâmetro
Exemplo 4
fn funcao(param1: i8, param2:f32) 
{
    println!("param1:{} param2:{}",param1,param2);
}

fn main()
{
 funcao(1,1.99);
}
Saída
param1:1 param2:1.99

Para que uma função retorne um valor de um tipo de dados, devemos declarar o corpo de nossa função e utilizar o comando return como a sintaxe abaixo:

Sintaxe
fn nome_funcao(<parametros>) -> tipo_retorno {
   //corpo
   return valor_retorno; 
}
Onde
tipo_retorno: Tipo de dado que será retornado pela função. Primitivo ou não
<parametros>: lista de parâmetros separados por (,)
return: Comando para retornar um valor de uma função

Um ou mais comandos return podem ser utilizados ao longo do corpo de uma função de acordo com a necessidade de validações para retorno.

Exemplo 5
//retornando string literal
fn funcao2() -> &'static str
{
    let retorno:&str = "string literal retorno";
    
    return retorno;
}

fn main ()
{

 let retorno1 = funcao();

 println!("{}",retorno1);
 
let retorno2:&str = funcao2();
println!("{}",retorno2);

}
Saída
string retorno
string literal retorno

Caso apenas uma expressão seja retornada no corpo da função, podemos apenas informar o valor retornado sem a palavra return como no exemplo abaixo:

Exemplo 6
fn funcao(p: i8) -> i8
{
  p*2 //return omitido
}

fn main() 
{
  println!("p depois: {}",funcao(2));
}
Saída
4

Quando simplesmente passamos um valor ou variável como argumento para uma função estamos passando apenas seu valor. Depois de usado, internamente na função através do parâmetro, esse valor será destruído.

Para que um parâmetro tenha seu valor alterado dentro de uma função, esse parâmetro deve ser declarado como mut como mostrado no exemplo a seguir:

Exemplo 7
fn funcao(mut p: i8)  
{
  p = p + 1; //mut para alteração
  println!("p alterado na função: {}",p);
  //p descartado
}

fn main() 
{
  let p: i8 = 1;
  println!("p antes: {}",p);
  funcao(p);	//passagem por valor
  println!("p depois: {}",p);
}
Saída
p antes: 1
p alterado na função: 2
p depois: 1

Para passarmos um argumento por referência para que seja alterado seu conteúdo de forma permanente, precisamos passar uma referência da variável que desejamos alterar.

De forma "semelhante" à C/C++, usamos os operadores (&) e (*). A palavra mut é prefixado com (&) para informar que o parâmetro que irá receber uma referência. O operador (*) é prefixado ao nome do parâmetro para acessar seu conteúdo de forma indireta.

Exemplo 8
fn funcao(p: &mut i8)
{
  *p = *p + 1;
  println!("p alterado na função: {}",p);
}

fn main() 
{
  let mut p: i8 = 1;

  println!("p antes: {}",p);
  funcao(&mut p);
  println!("p depois: {}",p);
}
Saída
p antes: 1
p alterado na função: 2
p depois: 2
  1. 22/05/2023 - versão inicial - Adição: Declaração, 'Função com parâmetro', 'Retornando valor' e 'Valor e Referência'