A煤n no tienes acceso a esta clase

Crea una cuenta y contin煤a viendo este curso

Uso de Slices

15/42
Recursos

Aportes 31

Preguntas 0

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesi贸n.

Los tres puntos al final de t.task[index + 1:]鈥 (operador ellipsis) es porque el segundo par谩metro del append no es un slice y la funci贸n append recibe un item, con este operador lo que hacemos es decirle a go que tome ese slice y lo 鈥渄esempaquete鈥 para que sean muchos par谩metros de 1 solo item y no un slice.

Ejemplo:

t.tasks = append(t.tasks, task1, task2, task3)

Lo que har铆a el operador de ellipsis seria pasar un slice a este formato de muchos par谩metros.

Creo que se deber铆a explicar en este punto el uso de los 3 puntos (鈥) no solamente decir que sino sale error de sintaxis.
Gracias igual a la comunidad que si lo menciona 馃槂

Los arreglos (arrays) son una estructura de dato de tama帽o fijo. Previamente tienen declarada su longitud y no puede ser mutada en tiempo de ejecuci贸n.

Los slices son una estructura de dato que se utiliza de manera similar a los arreglos pero con un comportamiento m谩s similar a las listas; esto en el aspecto de que tienen una longitud variable.

As铆 como los arrays, los slices definen su tipo con el uso de corchetes, pero con la diferencia de que no tenemos que indicar su tama帽o.

// Declaraci贸n de una variable de tipo slice
// con elementos de tipo string
var list []string

La funci贸n append sirve para agregar elementos a un slice. 脡sta recibe como par谩metros el slice y el elemento que se quiere agregar

// Agregando un elemento al slice
list = append(list, "element")

// Eliminando un elemento del slice
// [:index] Desde el inicio hasta el 铆ndice
// [index+1:] Desde el 铆ndice hasta el final
list = append(list[:index], list[index+1]...)

// Inicializando un slice
// cuando se hace con una l铆nea
// go no solicita la coma del 煤ltimo elemento
list := []string{"study","clean","pay"}

// Cuando se hace multi-l铆nea. si
list := []string{
	"study",
	"clean",
	"pay",
}

length := len(list)

El m茅todo len() nos sirve para saber la longitud de alguna estructura de datos, string, apuntador de un array o un channel.

Cuando eliminas un elemento del slice estas usando un comportamiento del slice que son los dos puntos (馃槂 que lo que hace es obtener los elementos que se indican ( inicio : final ) asi:
a[1:4] ; que basicamente es un rango de indices, similar a un substring(1,4).

11:35 No queda muy clara la explicaci贸n. Aqu铆 la explicaci贸n.

Un punto importante que encontr茅 en la documentaci贸n, los array en GO funcionan como un conjunto de valores, no como un conjunto de referencias, es decir, al enviarlo a una funci贸n, esta hace una copia de los valores. Los slices funcionan como referencias, internamente GO utiliza slices por encima de arreglos y recomienda usarlos siempre que sea posible:

https://www.godesignpatterns.com/2014/05/arrays-vs-slices.html

Yo entend铆 el operador (ellipsis) de Go como un operador de dispersi贸n.
Lo que se hizo en el arreglo es dispersar los elementos del slice como argumentos en la funci贸n append.
Aqu铆 un ejemplo:


package main

import "fmt"

func sumar(numeros ...int) int {
	result := 0
	for _, num := range numeros {
		result += num
	}
	return result
}

func main() {
	primos := []int{2, 3, 5, 7}
	fmt.Println(sumar(primos...)) // Resultado: 17
}

Implementaci贸n de la funci贸n append en los Go Docs:
![](

Y aqu铆 un ejemplo en Javascript que produce el mismo resultado:

const sumar = (w, x, y, z) => w + x + y + z;

const primos = [2, 3, 5, 7];

console.log(sumar(...primos)); // Resultado: 17

Para los del barrio que venimos sabiendo C, los arrays de aqui son los mismos de C, y los slices de golang no son mas que los malloc de C, pero en golang no hay que hacer free :v

Otra cosa, la manera de como el agrega elementos uno a uno expandiendo la memoria por cada elemento nuevo es una mala practica que pesa mucho en el performance, eso no se hace, si quieren entender porque es algo largo y complejo, pero en pocas palabras cada ves que agregas una nueva variable se hace limpieza y realocacion, a parte de que es en la memoria virtual la cua es lenta, asi que hay que tratar de evitar hacer esta operaciones a cada rato, la solucion? hacer allocacion de memoria exponencial

Si quieren que haga un blog explicando a profundidad y de como y porque implementar un sistema asi comenten y asi me animo

Humildemente, me parece que hay complicaciones extras sin necesidad, puede ser un slice normal y las funciones de manipulaci贸n del slice usan apuntadores para hacer paso de par谩metros por referencia.

El primer caso: recibe como par谩metros un slice y los elementos que se agregaran a ese slice.
El segundo caso: recibe como par谩metros dos slice.
Para el ejemplo de agregar elementos se usa el primer caso.
Para el ejemplo de remover tareas se usa el segundo caso.

Los slices tienen una forma de excluir e incluir 铆ndices seg煤n sea nuestra conveniencia, por ejemplo:

slice := []int{0,1,2,3,4,5,6}
fmt.Println(slice[:3])

nos mostrara en consola

[0 1 2] es decir se excluye el valor de la posici贸n 3 y se muestra sus antecesores.

fmt.Println(slice[2:4])

nos mostrar谩 en consola
[2 3] lo podemos ver como un rango de valores a mostrar, es decir se incluye el valor de la posici贸n 2 hasta la posici贸n 4 excluyendo este 煤ltimo del resultado.

fmt.Println(slice[4:])

nos mostrar谩 en consola
[4 5 6] es decir se incluye el valor del 铆ndice 4 en adelante
as铆 mismo podemos agregar un slice a otro slice

newSlice := []int{7,8,9}
slice = append(slice, newSlice鈥)
//nos mostrara en consola
//[0 1 2 3 4 5 6 7 8 9]
package main

import "fmt"


type taskList struct {
	tasks []*task
}

func(t *taskList) agregarALista(tl *task) {
	t.tasks = append(t.tasks, tl)
}

func (t *taskList) eliminarDeLista(index int) {
	// ... desempaquetar los elementos
	t.tasks = append(t.tasks[:index], t.tasks[index + 1:]...)
}

type task struct {
	nombre      string
	descripcion string
	completado  bool
}

func (t *task) marcarCompleta() {
	t.completado = true
}

func (t *task) actualizarDescripcion(desc string) {
	t.descripcion = desc
}

func (t *task) actualizarNombre( nombre string) {
	t.nombre = nombre
}

func main() {
	t0 := &task{
		nombre:      "Completar curso go",
		descripcion: "Completar el curso de go en esta semana",
	}
	t1 := &task{
		nombre:      "Completar curso Python",
		descripcion: "Completar el curso de go en esta semana",
	}
	t2 := &task{
		nombre:      "Completar curso Mongo",
		descripcion: "Completar el curso de go en esta semana",
	}
	

	lista := &taskList{
		tasks: []*task{
			t0, t1,
		},
	}

	fmt.Println(lista.tasks[0])

	fmt.Println(len(lista.tasks))

	lista.agregarALista(t2)

	fmt.Println(len(lista.tasks))

	lista.eliminarDeLista(1)
	fmt.Println(len(lista.tasks))

	
}

Genial 馃槂

//Arrays tama帽o fijo
var numbers1 [4]int
numbers2 := [鈥int{0,0,0,0}

//Slices tama帽o dinamico
slice1 := []int{2,3,4}

los rreglos son un poco diferente porque una vez dimensionados no se puede cambiar su longitud

los arreglos en go son inmutables

los slice son mucho mas poderoso sobre los arreglos porque son mas dinamicos

task []*task estamos agregando valores y no la referencia

loas struct tiene proiedades, como pueden ser arreglos

len para ver la Longitud del slice

append es muy poderosos para manejar slice, lo cual, los slice son muy dinamicos

Creo que se podria explicar un poco mas en detalle las funciones del slice al menos las que se usan en el ejemplo.
Yo siendo la primera vez que veo el lenguaje me qued贸 mas claro leyendo los comentarios

No podr铆amos tener un slice de punteros task sin tener que crear todo un struct (taskList)?

Por ejemplo:

taskList := []*task{}

Tiene m谩s sentido tener un struct solo si tenemos otros valores en taskList aparte del slice []*task

Tambi茅n hay que poner cuidado cuando usamos slices de apunteros, les dejo este post que da un buen ejemplo de un error que en mi opini贸n puede ser com煤n.

comparto una mi versi贸n de eliminar tarea, donde en vez de pasar el indice paso la tarea y la busco en la lista

func (ts *Tasks) deleteTask(t Task) error {
	idx := sort.Search(len(ts.tasks), func(i int) bool {
		return string(ts.tasks[i].name) >= t.name
	})

	fmt.Println(idx)

	if idx != -1 {
		ts.tasks = append(ts.tasks[:idx], ts.tasks[idx + 1:]...)
		return nil
	} else {
		return errors.New("La tarea a eliminar no se encuentra en la lista actual")
	}
}

Prara quienes quedaron en duda con el trabajo de los slices y su diferencia con los arrays les dejo aca las notas de lo que investigu茅

Arrays vs Slices

Go tiene la particularidad de tener 2 tipos primitivos de coleccion de datos

<h3>Arrays</h3>

Los array en Go son tratados como un tipo de dato, no como un apuntador o una referencia a un objeto, por lo que reasignarlo o pasarlo como argumento implica una copia uno a uno de los valores que lo conforman (por lo que podria llegar a ser realmente costoso).

Estos datos son de tama帽o estatico los cuales almacenan una cantidad de elementos de un mismo tipo en un espacio de memoria la cual es ocupada tan pronto es declarado el array.

El tama帽o del array es parte del tipo de dato por lo que no es posible asignar un [4]int a un [3]int.

[N]Type
[N]Type{value1, value2, ..., valueN}
[...]Type{value1, value2, ..., valueN}
<h3>Slices</h3>

Los slice son un tipo referenciable de dato que almacena una cantidad de elementos del mismo tipo, a diferencia de los array estos tienen un tama帽o din谩mico y se pasan por referencia en la asignaci贸n y como argumento.

Un slice consiste de 3 elementos: la longitud, la capacidad y el apuntador al array que contiene los datos.

Puede pensarse un slice como la implementaci贸n nativa de Go para los ArrayList o Vector, trayendo consigo las virtudes y defectos inherentes a esta estructura de datos.

make([]Type, length, capacity)
make([]Type, length)
[]Type{}
[]Type{value1, value2, ..., valueN}

Qu茅 buen profe !!! todo muy claro. Mil gracias

Buenas, este ser铆a mi aporte del c贸digo de esta clase:

package main

import "fmt"

type task struct {
	name        string
	description string
	completed   bool
}

type tasksList []task

func (t *task) update(tasks ...interface{}) {
	for i := 0; i < len(tasks); i++ {
		switch i {
		case 0:
			if tasks[i] != nil {
				t.name = tasks[0].(string)
			}
		case 1:
			if tasks[i] != nil {
				t.description = tasks[1].(string)
			}
		case 2:
			t.completed = tasks[2].(bool)
		}
	}
}

func (t task) add(tasks *tasksList) {
	*tasks = append(*tasks, t)
}

func (t *tasksList) remove(i int) {
	temp := *t
	temp = append(temp[:i], temp[i+1:]...)
	*t = temp
}

func main() {
	t := task{}
	var tasks tasksList

	t.update("Curso de GO", "Completar el curso de GO en esta semana", false)
	t.add(&tasks)

	t.update("Curso de Ingl茅s", "Empezar el curso de Ingl茅s cuando me mude", false)
	t.add(&tasks)

	t.update("Curso de SQL", "Empezar el curso de SQL cuando me mude", false)
	t.add(&tasks)

	tasks.remove(1)

	for _, v := range tasks {
		fmt.Printf("%v: %v. Completado: %v\n", v.name, v.description, v.completed)
	}
}

package main

import (
	"fmt"
)

type taskList struct {
	tasks []*task
}

func (t *taskList) agregarALista( tl *task) {
	t.tasks = append(t.tasks, tl)
}

func ( t *taskList) eliminarDeLista(index int) {
	t.tasks = append(t.tasks[:index], t.tasks[index + 1:]...)
}

type task struct{
	nombre string
	descripcion string
	completado bool
}

func (t *task) marcarCompleta(){
	t.completado = true
}

func (t *task) actualizaDescripcion(descripcion string) {
	t.descripcion = descripcion
}

func (t *task) actualizaNombre(nombre string) {
	t.nombre = nombre
}

func main() {
	t1 := &task{
		nombre: 	 "Completar mi curso de Go::",
		descripcion: "Completare mi curso de Go de Platzi en esta semana::",
	}

	t2 := &task{
		nombre: 	 "Completar mi curso de JavaScript::",
		descripcion: "Completare mi curso de JavaScript de Platzi en esta semana::",
	}

	t3 := &task{
		nombre: 	 "Completar mi curso de NodeJS::",
		descripcion: "Completare mi curso de NodeJS de Platzi en esta semana::",
	}

	lista := &taskList {
		tasks: []*task{
			t1, t2,
		},
	}

	fmt.Println(lista.tasks[0])
	lista.agregarALista(t3)
	fmt.Println("elementos:", len(lista.tasks))

	lista.eliminarDeLista(1)
	fmt.Println("elementos:", len(lista.tasks))

}

Me quedaron dudas con el uso de los tres puntos. Se utiliza cuando no se sabe la aridad o la cantidad de argumentos que puede tener una funci贸n, como el n煤mero de elementos es variable, la funci贸n se llama con esta sintaxis que tiene Go. Ac谩 hay un ejemplo que me gener贸 mayor claridad. Adem谩s se habla de manera amplia del concepto.

func remove(slice []int, s int) []int {
    return append(slice[:s], slice[s+1:]...)
}

Basicamente toma la primera parte del slice hasta donde est谩 el elemento que queremos eliminar y luego le agregamos el resto del slice despu茅s del elemento que queremos eliminar. De esta forma mantenemos el orden y eliminamos el elemento.