8. Estruturas básicas e expressões do Groovy¶
Nextflow é uma linguagem específica de domínio (DSL) implementada sobre a linguagem de programação Groovy, que por sua vez é um superconjunto da linguagem de programação Java. Isso significa que o Nextflow pode executar qualquer código Groovy ou Java.
Aqui estão algumas sintaxes Groovy importantes que são comumente usadas no Nextflow.
8.1 Imprimindo valores¶
Imprimir algo é tão fácil quanto usar um dos métodos print
ou println
.
A única diferença entre os dois é que o método println
anexa implicitamente um caractere de nova linha à string impressa.
Tip
Parênteses para invocações de função são opcionais. Portanto, a seguinte sintaxe também é válida:
8.2 Comentários¶
Os comentários usam a mesma sintaxe das linguagens de programação da família C:
8.3 Variáveis¶
Para definir uma variável, basta atribuir um valor a ela:
As variáveis locais são definidas usando a palavra-chave def
:
O def
deve ser sempre usado ao definir variáveis locais para uma função ou clausura.
8.4 Listas¶
Um objeto List pode ser definido colocando os itens da lista entre colchetes:
Você pode acessar um determinado item na lista com a notação de colchetes (índices começam em 0
) ou usando o método get
:
Para obter o comprimento de uma lista, você pode usar o método size
:
Usamos a palavra-chave assert
para testar se uma condição é verdadeira (semelhante a uma função if
). Aqui, o Groovy não imprimirá nada se estiver correto, caso contrário, gerará uma mensagem AssertionError.
Note
Esta afirmação deve estar correta, tente alterá-la para uma incorreta.
As listas também podem ser indexadas com índices negativos e intervalos invertidos.
Info
Na afirmação da última linha, estamos referenciando a lista inicial e convertendo-a com um intervalo "abreviado" (..
), para executar do -1º elemento (2), o último, ao 0º elemento (0), o primeiro.
Objetos List implementam todos os métodos fornecidos pela interface java.util.List, mais os métodos de extensão fornecidos pelo Groovy.
8.5 Mapas¶
Os mapas são como listas que possuem uma chave arbitrária em vez de um número inteiro. Portanto, a sintaxe é bem parecida.
Os mapas podem ser acessados em uma sintaxe convencional de colchetes ou como se a chave fosse uma propriedade do mapa.
Clique no ícone para ver explicações no código.
- Usando colchetes.
- Usando a notação de ponto.
- Usando o método
get
.
Para adicionar dados ou modificar um mapa, a sintaxe é semelhante à adição de valores a uma lista:
- Usando colchetes.
- Usando a notação de ponto.
- Usando o método put.
Objetos Map implementam todos os métodos fornecidos pela interface java.util.Map, mais os métodos de extensão fornecidos pelo Groovy.
8.6 Interpolação de Strings¶
Strings podem ser definidas colocando-as entre aspas simples ('') ou duplas ("").
Info
Observe o uso diferente das sintaxes $
e ${..}
para interpolar expressões de valor em uma string.
A variável $x
não foi expandida, pois estava entre aspas simples.
Por fim, strings também podem ser definidas usando o caractere /
como delimitador. Elas são conhecidas como strings com barras e são úteis para definir expressões regulares e padrões, pois não há necessidade de escapar as barras invertidas. Assim como as strings de aspas duplas, elas permitem interpolar variáveis prefixadas com um caractere $
.
Tente o seguinte para ver a diferença:
8.7 Strings de várias linhas¶
Um bloco de texto que abrange várias linhas pode ser definido delimitando-o com aspas simples ou duplas triplas:
Por fim, strings de várias linhas também podem ser definidas com strings com barras. Por exemplo:
Info
Como antes, strings de várias linhas dentro de aspas duplas e caracteres de barra suportam interpolação de variável, enquanto strings de várias linhas com aspas simples não.
8.8 Declarações condicionais com if¶
A instrução if
usa a mesma sintaxe comum em outras linguagens de programação, como Java, C, JavaScript, etc.
O ramo else
é opcional. Além disso, as chaves são opcionais quando a ramificação define apenas uma única instrução.
Tip
null
, strings vazias e coleções (mapas e listas) vazias são avaliadas como false
.
Portanto, uma declaração como:
Pode ser escrita como:
Veja o Groovy-Truth para mais detalhes.
Tip
Em alguns casos, pode ser útil substituir a instrução if
por uma expressão ternária (também conhecida como expressão condicional). Por exemplo:
A declaração anterior pode ser ainda mais simplificada usando o operador Elvis, como mostrado abaixo:
8.9 Declarações de loop com for¶
A sintaxe clássica do loop for
é suportada como mostrado aqui:
A iteração sobre objetos de lista também é possível usando a sintaxe abaixo:
8.10 Funções¶
É possível definir uma função personalizada em um script, conforme mostrado aqui:
Uma função pode receber vários argumentos, separando-os com uma vírgula. A palavra-chave return
pode ser omitida e a função retorna implicitamente o valor da última expressão avaliada. Além disso, tipos explícitos podem ser omitidos, embora não sejam recomendados:
8.11 Clausuras¶
Clausuras são o canivete suíço da programação com Nextflow/Groovy. Resumindo, uma clausura é um bloco de código que pode ser passado como um argumento para uma função. Clausuras também podem ser usadas para definir uma função anônima.
Mais formalmente, uma clausura permite a definição de funções como objetos de primeira classe.
As chaves ao redor da expressão it * it
informam ao interpretador de scripts para tratar essa expressão como código. O identificador it
é uma variável implícita que representa o valor que é passado para a função quando ela é invocada.
Depois de compilado, o objeto de função é atribuído à variável quadrado
como qualquer outra atribuição de variável mostrada anteriormente. Para invocar a execução da clausura, use o método especial call
ou simplesmente use os parênteses para especificar o(s) parâmetro(s) da clausura. Por exemplo:
Da forma como foi mostrado, isso pode não parecer interessante, mas agora podemos passar a função quadrado
como um argumento para outras funções ou métodos. Algumas funções embutidas aceitam uma função como esta como um argumento. Um exemplo é o método collect
em listas:
Por padrão, as clausuras recebem um único parâmetro chamado it
. Para dar a ele um nome diferente, use a sintaxe ->
. Por exemplo:
Também é possível definir clausuras com vários parâmetros com nomes personalizados.
Por exemplo, quando o método each()
é aplicado a um mapa, ele pode receber uma clausura com dois argumentos, para os quais passa o par chave-valor para cada entrada no objeto Map
. Por exemplo:
Uma clausura tem duas outras características importantes.
Primeiro, ela pode acessar e modificar variáveis no escopo em que está definida.
Em segundo lugar, uma clausura pode ser definida de maneira anônima, o que significa que não recebe um nome e é definida no local em que precisa ser usada.
Para um exemplo mostrando esses dois recursos, consulte o seguinte trecho de código:
- Define uma variável global.
- Define um objeto de mapa.
- Chama o método
each
passando o objeto de clausura que modifica a variávelresultado
.
Saiba mais sobre clausuras na documentação do Groovy.
8.12 Mais recursos¶
A documentação completa da linguagem Groovy está disponível nesse link.
Um ótimo recurso para dominar a sintaxe do Apache Groovy é o livro: Groovy in Action.