-
Notifications
You must be signed in to change notification settings - Fork 83
/
Copy pathREADME.md
194 lines (145 loc) · 10.7 KB
/
README.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
## <a name="golang_questions"></a> Вопросы по языку Golang
### <a name="1"></a> 1. Что из себя представляет тип данных string в языке Golang? Можно ли изменить определенный символ в строке? Что происходит при склеивании строк?
Строка Go - это байтовый срез, предназначенный только для чтения, который может содержать байты любого типа и иметь произвольную длину. Строка неизменяемая и изменить определенный символ в конкретной строке нельзя. Создается новая строка (в простейшем случае).
### <a name="2"></a> 2. Вытекающий вопрос — как эффективно склеивать множество строк?
Например, чтобы избавиться от лишних аллокаций, можно воспользоваться типом strings.Builder и методом WriteString:
```go
func join(strs ...string) string {
var sb strings.Builder
for _, str := range strs {
sb.WriteString(str)
}
return sb.String()
}
```
И никто не мешает пользоваться пакетом strings.
### <a name="8"></a> 8. Как задать направление канала?
Мы можем задать направление передачи сообщений в канале, сделав его только отправляющим или принимающим. Например:
```go
func f(c chan<- string)
```
и канал `c` будет только отправлять сообщение. Попытка получить сообщение из канала c вызовет ошибку компилирования. Также мы можем изменить функцию `f`:
```go
func f(c <-chan string)
```
Существуют и двунаправленные каналы, которые могут быть переданы в функцию, принимающую только принимающие или отправляющие каналы. Но только отправляющие или принимающие каналы не могут быть переданы в функцию, требующую двунаправленного канала!
### <a name="9"></a> 9. Напишите собственную функцию Sleep, используя time.After
```go
func sleep(s int) {
<- time.After(time.Second * time.Duration(s)):
}
```
### <a name="10"></a> 10. Что такое буферизированный канал? Как создать такой канал с ёмкостью в 20 сообщений?
При инициализации канала можно использовать второй параметр:
```go
c := make(chan int, 1)
```
и мы получим буферизированный канал с ёмкостью __1__. Обычно каналы работают синхронно - каждая из сторон ждёт, когда другая сможет получить или передать сообщение. Но буферизованный канал работает асинхронно — получение или отправка сообщения не заставляют стороны останавливаться. Но канал теряет пропускную способность, когда он занят, в данном случае, если мы отправим в канал __1__ сообщение, то мы не сможем отправить туда ещё одно до тех пор, пока первое не будет получено.
### <a name="11"></a> 11. Напишите программу, которая меняет местами два числа (x := 1; y := 2; swap(&x, &y) должно дать x=2 и y=1)
```go
func main() {
x := 1
y := 2
swap(&x, &y)
fmt.Println(x, y)
}
func swap(x, y *int) {
*x, *y = *y, *x
}
```
### <a name="12"></a> 12. Какое будет значение у переменной x после выполнения программы?
```go
func square(x *float64) {
*x = *x * *x
}
func main() {
x := 1.5
square(&x)
fmt.Println(x)
}
```
<details>
<summary>Ответ</summary>
Ответ: 2.25
</details>
### <a name="13"></a> 13. Какое значение примет выражение (true && false) || (false && true) || !(false && false)?
```go
fmt.Println((true && false) || (false && true) || !(false && false))
```
<details>
<summary>Ответ</summary>
Ответ: true
</details>
### <a name="14"></a> 14. Мы знаем, что в десятичной системе самое большое число из одной цифры - это 9, а из двух - 99. В бинарной системе самое большое число из двух цифр это 11 (3), самое большое число из трех цифр это 111 (7) и самое большое число из 4 цифр это 1111 (15). Вопрос: каково самое большое число из 8 цифр?
Подсказка:
1. 10<sup>1</sup> - 1 = 9, a 10<sup>2</sup> - 1 = 99 (Решение через знание степеней 2)
2. 11110 это 15 * 2 = 30, а 111100 это 15 * 2 * 2 = 60 (Решение через битовый сдвиг)
<details>
<summary>Ответ</summary>
Ответ: 255
</details>
### <a name="15"></a> 15. Что выведет следующая программа?
```go
package main
import "fmt"
func main() {
i := 65
fmt.Println(string(i))
}
```
**Варианты:**
1. A
2. 65
3. Ошибка компиляции
4. Нет правильного ответа
5. Я не знаю
<details>
<summary>Ответ</summary>
Ответ: А
</details>
### <a name="16"></a> 16. Что выведет следующая программа?
```go
package main
import "fmt"
func main() {
a := [5]int{1, 2, 3, 4, 5}
t := a[3:4:4]
fmt.Prinln(t[0])
}
```
**Варианты:**
1. 3
2. 4
3. Ошибка компиляции
4. Нет правильного ответа
5. Я не знаю
<details>
<summary>Ответ</summary>
Ответ: 4
</details>
### <a name="17"></a> 17.Как работает Garbage Collection в Go?
Garbage Collection - это процесс освобождения места в памяти, которое больше не используется. В документации указано следующее:
```go
GC выполняется конкурентно (concurrent), одновременно с потоками мутатора (mutator), в точном соответствии с типом (этот принцип также известен как чувствительность к типу), допускается парааллельная выполнение нескольких потоков GC. Это конкурентная пометка и очистка (mark-sweep), при которой используется барьер записи (write barrier). При этом в процессе ничего не генерируется и не сжимается. Освобождение памяти выполняется на основе размера, выделенного для каждой программы Р, чтобы в общем случае минимизировать фрагментацию и избежать блокировок.
```
В основе работы GC Go лежит "трехцветный алгоритм". Официальное название "трехцветный алгоритм пометки и очистки". Использует барьер памяти. Главный принцип алгоритма трехцветной пометки и очистки состоит в разделении объектов, находящихся куче, на три набора, в соответствии с "цветом". Условно разделяются на 3 цвета:
- черные объекты - гарантированно не имеют указателей на белые объекты;
- серые объекты - могут иметь указатели на белые объекты;
- белые объекты - на них могут ссылаться некоторые серые объекты и сами некоторые белые объекты могут ссылаться на некоторые черные.
Краткий алгоритм:
1. Все объекты сначала белые;
2. Идет перебор "корневых" объектов, помечаются как серые. Корневые - это объекты к которым можно обращаться напрямую, например глобальные переменные, элементы в стеке и т.д.
3. Идет перебор серых объектов, проверяются ссылки на другие объекты и помечаются на черные объекты. Если есть ссылка на белый объект, то белый становится серым.
4. Продолжается до тех пор, пока не будут перебраны все серые объекты.
5. Оставшиеся после перебора белые объекты считаются недостижимыми и занимаемая ими область памяти может быть освобождена.
Есть еще Мутатор - это приложение, работающее во время сборки мусора. Вызывает функцию барьера записи. Выполняется каждый раз, когда меняется указатель в куче. После изменения указателя объект считается достижимым и помечается как серый.
### <a name="18"></a> 18.Что такое interface, как они работают в Go?
`// todo`
### <a name="19"></a> 19.Что такое slice, как устроены и чем отличаются от массивов?
`// todo`
### <a name="20"></a> 20.Что такое len и capacity в slice Go?
`// todo`
### <a name="21"></a> 21.Возможно ли предугадать, что GC отработает за константное время N?
`// todo`
### <a name="22"></a> 22.Что будет, если создать канал и отправить туда запись, но у него нет читателей?
`// todo`