Percursos
/
Go
Go
/
Exercícios
/
Truques com cartas
Truques com cartas

Truques com cartas

Exercício de aprendizagem

Introdução

Slices

Os slices em Go são semelhantes a listas ou arrays noutras linguagens. Contêm vários elementos de um tipo específico (ou interface).

Os slices em Go baseiam-se em arrays. Os arrays têm um tamanho fixo. Um slice, por outro lado, é uma vista flexível e de tamanho dinâmico dos elementos de um array.

Um slice escreve-se como []T, em que T é o tipo dos elementos do slice:

var empty []int                 // an empty slice
withData := []int{0,1,2,3,4,5}  // a slice pre-filled with some data

Podes obter ou definir um elemento num determinado índice com base zero usando a notação de parênteses retos:

withData[1] = 5
x := withData[1] // x is now 5

Podes criar um novo slice a partir de um slice existente obtendo um intervalo de elementos. Mais uma vez, usando a notação de parênteses retos, mas especificando tanto um índice inicial (inclusive) como um índice final (exclusive). Se não especificares um índice inicial, este assume o valor 0. Se não especificares um índice final, este assume o comprimento do slice.

newSlice := withData[2:4]
// => []int{2,3}
newSlice := withData[:2]
// => []int{0,1}
newSlice := withData[2:]
// => []int{2,3,4,5}
newSlice := withData[:]
// => []int{0,1,2,3,4,5}

Podes adicionar elementos a um slice usando a função append. Abaixo, acrescentamos 4 e 2 ao slice a.

a := []int{1, 3}
a = append(a, 4, 2)
// => []int{1,3,4,2}

A função append devolve sempre um novo slice e, quando só queremos acrescentar elementos a um slice existente, é comum voltar a atribuí-lo à variável do slice que passamos como primeiro argumento, como fizemos acima.

A função append também pode ser usada para combinar dois slices:

nextSlice := []int{100,101,102}
newSlice  := append(withData, nextSlice...)
// => []int{0,1,2,3,4,5,100,101,102}

Funções variádicas

Normalmente, as funções em Go aceitam apenas um número fixo de argumentos. No entanto, também é possível escrever funções variádicas em Go.

Uma função variádica é uma função que aceita um número variável de argumentos.

Se o tipo do último parâmetro numa definição de função for precedido de reticências ..., então a função pode aceitar qualquer número de argumentos para esse parâmetro.

func find(a int, b ...int) {
    // ...
}

Na função acima, o parâmetro b é variádico e podemos passar 0 ou mais argumentos a b.

find(5, 6)
find(5, 6, 7)
find(5)
Caution

O parâmetro variádico tem de ser o último parâmetro da função.

As funções variádicas funcionam convertendo o número variável de argumentos num slice do tipo do parâmetro variádico.

Aqui está um exemplo de implementação de uma função variádica.

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)

    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            return
        }
    }

    fmt.Println(num, "not found in ", nums)
}

func main() {
    find(89, 90, 91, 95)
    // =>
    // type of nums is []int
    // 89 not found in  [90 91 95]

    find(45, 56, 67, 45, 90, 109)
    // =>
    // type of nums is []int
    // 45 found at index 2 in [56 67 45 90 109]

    find(87)
    // =>
    // type of nums is []int
    // 87 not found in  []
}

Na linha find(89, 90, 91, 95) do programa acima, os argumentos variáveis da função find são 90, 91 e 95. A função find espera um parâmetro variádico do tipo int depois de num. Por isso, estes três argumentos serão convertidos pelo compilador num slice do tipo int, []int{90, 91, 95}, e depois será passado à função find como nums.

Por vezes, já tens um slice e queres passá-lo a uma função variádica. Podes conseguir isso passando o slice seguido de .... Isso diz ao compilador para usar o slice tal como está dentro da função variádica. O passo descrito acima, em que é criado um slice, é simplesmente omitido neste caso.

list := []int{1, 2, 3}
find(1, list...) // "find" defined as shown above

Instruções

Como futura maga, a Elyse precisa de praticar alguns conceitos básicos. Tem uma pilha de cartas que quer manipular.

Para simplificar um pouco, só usa as cartas de 1 a 10.

1. Cria um slice com determinadas cartas

Quando está a praticar com as cartas, a Elyse gosta de começar pelas suas três cartas favoritas do baralho: 2, 6 e 9. Escreve uma função FavoriteCards que devolve um slice com essas cartas por essa ordem.

cards := FavoriteCards()
fmt.Println(cards)
// Output: [2 6 9]

2. Obter uma carta de uma pilha

Devolve a carta na posição index da pilha indicada.

card := GetItem([]int{1, 2, 4, 1}, 2) // card == 4

Se o índice estiver fora dos limites (ou seja, se for negativo ou ultrapassar o fim da pilha), queremos devolver -1:

card := GetItem([]int{1, 2, 4, 1}, 10) // card == -1
Note

Por convenção em Go, devolve-se um erro em vez de devolver um valor "fora dos limites". Aqui, o valor "fora dos limites" é -1 quando se espera um número inteiro positivo. Ao devolver um erro, considera-se idiomático devolver o zero value juntamente com o erro. Devolver um erro com o valor devolvido adequado será abordado num exercício futuro.

3. Trocar uma carta na pilha

Troca a carta na posição index pela nova carta fornecida e devolve a pilha ajustada. Repara que isto vai modificar o slice que recebes, o que é o comportamento esperado.

index := 2
newCard := 6
cards := SetItem([]int{1, 2, 4, 1}, index, newCard)
fmt.Println(cards)
// Output: [1 2 6 1]

Se o índice estiver fora dos limites (ou seja, se for negativo ou ultrapassar o fim da pilha), queremos acrescentar a nova carta ao fim da pilha:

index := -1
newCard := 6
cards := SetItem([]int{1, 2, 4, 1}, index, newCard)
fmt.Println(cards)
// Output: [1 2 4 1 6]

4. Adicionar cartas ao topo da pilha

Adiciona a(s) carta(s) indicada(s) no parâmetro value ao topo da pilha.

slice := []int{3, 2, 6, 4, 8}
cards := PrependItems(slice, 5, 1)
fmt.Println(cards)
// Output: [5 1 3 2 6 4 8]

Se não for dado nenhum argumento para o parâmetro value, o resultado é igual ao slice original.

slice := []int{3, 2, 6, 4, 8}
cards := PrependItems(slice)
fmt.Println(cards)
// Output: [3 2 6 4 8]

5. Remover uma carta da pilha

Remove a carta na posição index da pilha e devolve a pilha. Repara que isto pode modificar o slice que recebes, o que não faz mal.

cards := RemoveItem([]int{3, 2, 6, 4, 8}, 2)
fmt.Println(cards)
// Output: [3 2 4 8]

Se o índice estiver fora dos limites (ou seja, se for negativo ou ultrapassar o fim da pilha), queremos deixar a pilha inalterada:

cards := RemoveItem([]int{3, 2, 6, 4, 8}, 11)
fmt.Println(cards)
// Output: [3 2 6 4 8]
Editar via GitHub A ligação abre numa nova janela ou separador
Go Exercism

Estás pronto para começar Truques com cartas?

Inscreve-te no Exercism para aprenderes e dominares Go com 34 conceitos165 exercícios, e mentoria humana real, tudo grátis.