/L1

Primary LanguageGo

L1

Tasks

main library test task
1 main Дана структура Human. Реализовать встраивание методов в структуре Action от родительской структуры Human
2 main Написать программу, которая конкурентно рассчитает значение квадратов чисел взятых из массива и выведет их квадраты в stdout
3 main Дана последовательность чисел. Найти сумму их квадратов с использованием конкурентных вычислений
4 main Реализовать постоянную запись данных в канал (главный поток). Реализовать набор из N воркеров, которые читают произвольные данные из канала и выводят в stdout. Необходима возможность выбора количества воркеров при старте.
5 main Разработать программу, которая будет последовательно отправлять значения в канал, а с другой стороны канала — читать. По истечению N секунд программа должна завершаться
6 main Реализовать все возможные способы остановки выполнения горутины
7 main Реализовать конкурентную запись данных в map
8 main test Дана переменная int64. Разработать программу которая устанавливает i-й бит в 1 или 0
9 main internal/pipeline Разработать конвейер чисел. Даны два канала: в первый пишутся числа (x) из массива, во второй — результат операции x*2, после чего данные из второго канала должны выводиться в stdout
10 main Дана последовательность температурных колебаний: -25.4, -27.0 13.0, 19.0, 15.5, 24.5, -21.0, 32.5. Объединить данные значения в группы с шагом в 10 градусов. Последовательность в подмножноствах не важна
11 main Реализовать пересечение двух неупорядоченных множеств
12 main Имеется последовательность строк - (cat, cat, dog, cat, tree) создать для нее собственное множество
13 main Поменять местами два числа без создания временной переменной
14 main Разработать программу, которая в рантайме способна определить тип переменной: int, string, bool, channel из переменной типа interface{}
15 main К каким негативным последствиям может привести данный фрагмент кода, и как это исправить? Приведите корректный пример реализации.
16 main internal/quicksort test Реализовать быструю сортировку массива (quicksort) встроенными методами языка
17 main internal/bisect test Реализовать бинарный поиск встроенными методами языка
18 main Реализовать структуру-счетчик, которая будет инкрементироваться в конкурентной среде. По завершению программа должна выводить итоговое значение счетчика
19 main Разработать программу, которая переворачивает подаваемую на ход строку (например: «главрыба — абырвалг»). Символы могут быть unicode.
20 main Разработать программу, которая переворачивает слова в строке. Пример: «snow dog sun — sun dog snow».
21 main Реализовать паттерн «адаптер» на любом примере
22 main Разработать программу, которая перемножает, делит, складывает, вычитает две числовых переменных a,b, значение которых > 2^20
23 main Удалить i-ый элемент из слайса
24 main Разработать программу нахождения расстояния между двумя точками, которые представлены в виде структуры Point с инкапсулированными параметрами x,y и конструктором.
25 main internal/sleep Реализовать собственную функцию sleep
26 main Разработать программу, которая проверяет, что все символы в строке уникальные. Функция проверки должна быть регистронезависимой

Colloquial questions

Какой самый эффективный способ конкатенации строк?

According to docs, strings.Builder is optimized for for efficient string building.

Usage example:

package main

import (
	"fmt"
	"strings"
)

func main() {
	var b strings.Builder

	fragments := []string{"fragment 1", "fragment 2", "fragment 3"}
	for _, fragment := range fragments {
		b.WriteString(fragment)
		b.WriteString(". ")
	}
	fmt.Println(b.String()) // fragment 1. fragment 2. fragment 3.
}

Что такое интерфейсы, как они применяются в Go?

Interfaces are type contracts that declare what methods must be implemented. Interfaces are implemented implicitly in Go. There are 3 different ways of using interfaces.

The first one is to use an empty interface interface{} that is implemented by everything in Go to make a function accept anything as an argument. interface{} is also aliased as any and usually it is more convenient to use this form.

The second one is to use an interface to specify the methods that the type should implement. This allows us to write less coupled code and simplifies testing.

The third one is to use an interface to declare a type constraint for generic code.

Чем отличаются RWMutex от Mutex?

Mutex supports only one kind of Lock, whereas RWMutex supports locking for reading (RLock/RUnlock) and for writing (Lock, Unlock).

RWMutex can have multiple readers but only one writer. When Lock is called (even before the lock is aquired), it blocks RLock.

Чем отличаются буферизированные и не буферизированные каналы?

Buffered channels have non-zero capacity. They can store a number of values inside. This leads to writing being non-blocking (unless the channel buffer is already full). Reading is non-blocking as well (unless the channel buffer is empty).

Also, the buffer can store values even after close has been called. Of course, writing new values after closing a channel would lead to a panic. Reading from a closed channel returns a default value anyway.

Какой размер у структуры struct{}{}?

Size of struct{}{} is 0 byte. Every empty struct value is the same object, so Go doesn't need any more memory for new copies.

package main

import (
	"fmt"
	"unsafe"
)

func main() {
	fmt.Println(unsafe.Sizeof(struct{}{})) // 0
}

Есть ли в Go перегрузка методов или операторов?

No, it was considered to be too much complications for too little value. Go, however, supports generics, interfaces, variadic functions and struct embedding that can be used to offer somewhat similar capabilities.

В какой последовательности будут выведены элементы map[int]int?

Maps are unordered in Go, so the order is arbitrary.

В чем разница make и new?

make allocates memory for and initializes composite data structures, such as slices, maps and channels. It returns an object itself, not a pointer to it.

new returns a pointer to a default value of type. It does not initialize underlying structure of slices, maps and channels (it just returns nil for them).

Сколько существует способов задать переменную типа slice или map?

// 5 ways of declaring a slice
var A []int            // nil
B := make([]int, 0)    // initialized, 0 len, 0 cap
C := make([]int, 0, 5) // initialized, 0 len, 5 cap
D := []int{0, 1}

arr := [3]int{0, 1, 2}
E := arr[1:]

// another file
// 4 ways of declaring a map
var A map[int]int         // nil
B := make(map[int]int)    // initialized, small size
C := make(map[int]int, 5) // initialized, enough for 5 ints
D := map[int]int{0: 1, 1: 2}

Что выведет данная программа и почему?

func update(p *int) {
  b := 2
  p = &b
}

func main() {
  var (
     a = 1
     p = &a
  )
  fmt.Println(*p)
  update(p)
  fmt.Println(*p)
}

The program prints 1, 1 because of a mistake in the update function. Developer mixed up pointer dereference and taking a pointer.

The code can be fixed like this:

func update(p *int) {
	b := 2
	*p = b // fixed line
}

Now it prints out 1, 2.

Что выведет данная программа и почему?

func main() {
  wg := sync.WaitGroup{}
  for i := 0; i < 5; i++ {
     wg.Add(1)
     go func(wg sync.WaitGroup, i int) {
        fmt.Println(i)
        wg.Done()
     }(wg, i)
  }
  wg.Wait()
  fmt.Println("exit")
}

This program is deadlocking because of wg copying. sync.WaitGroup contains a noCopy field indicating that sync.WaitGroup values must not be copied after the first use.

The goroutines are using a copy of wg, along with a copy of the underlying fields, so the invocation of wg.Done does not affect the semaphore of "external" wg in the main goroutine.

To fix this issue one might either make wg argument a pointer, or make use of closures by removing the argument altogether.

Then it would print numbers 0 to 4 in arbitrary order and exit.

Что выведет данная программа и почему?

func main() {
  n := 0
  if true {
     n := 1
     n++
  }
  fmt.Println(n)
}

The program prints out 0, because the variable is shadowed in the if statement, so all the modifications to n inside the if statement do not affect external n.

This can be fixed by replacing := (declaration operator) with = (assignment operator). Then the program would print out 2

Что выведет данная программа и почему?

func someAction(v []int8, b int8) {
  v[0] = 100
  v = append(v, b)
}

func main() {
  var a = []int8{1, 2, 3, 4, 5}
  someAction(a, 6)
  fmt.Println(a)
}

The program prints out [100, 2, 3, 4, 5] because v[0] = 100 affects the underlying array of v, which is the same as that of a, but v = append(v, b) reassigns v to point to a new array, separate from a's.

To be able to change the array of an external (relative to a function) slice, the argument must be a pointer and all the internal operations have to be modified accordingly.

func someAction(v *[]int8, b int8) {
	(*v)[0] = 100
	(*v) = append(*v, b)
}

func main() {
	a := []int8{1, 2, 3, 4, 5}
	someAction(&a, 6)
	fmt.Println(a)
}

This program would print out [100, 2, 3, 4, 5, 6].

Что выведет данная программа и почему?

func main() {
  slice := []string{"a", "a"}

  func(slice []string) {
     slice = append(slice, "a")
     slice[0] = "b"
     slice[1] = "b"
     fmt.Print(slice)
  }(slice)
  fmt.Print(slice)
}

The program prints out [b b a][a a] because the slice variable is reassigned to a slice different from the external one, so all the modifications affect the inner slice only.

To fix this, the argument has to be made a pointer and all the operations with slice have to be modified accordingly.

func main() {
	slice := []string{"a", "a"}

	func(slice *[]string) {
		*slice = append(*slice, "a")
		(*slice)[0] = "b"
		(*slice)[1] = "b"
		fmt.Print(slice)
	}(&slice)
	fmt.Print(slice)
}

Then the program prints out &[b b a][b b a]