├── go.mod ├── go.sum ├── homework ├── allocator │ └── homework_test.go ├── channels │ └── homework_test.go ├── contexts │ └── homework_test.go ├── data_types │ └── homework_test.go ├── errors │ └── homework_test.go ├── functions │ └── homework_test.go ├── garbage_collector │ └── homework_test.go ├── generics_and_reflection │ └── homework_test.go ├── goroutines_and_scheduler │ └── homework_test.go ├── interfaces │ └── homework_test.go ├── maps │ └── homewrok_test.go ├── slices_and_arrays │ └── homework_test.go ├── strings │ └── homework_test.go ├── structs │ └── homework_test.go └── sync_primitives │ └── homework_test.go ├── interviews └── data_types │ ├── endianness │ └── main.go │ ├── endianness_check │ └── main.go │ ├── int_overflow │ └── main.go │ ├── inversion │ └── main.go │ ├── octal_system │ └── main.go │ ├── overflow_detection │ └── main.go │ ├── pointer_to_pointer_correct │ └── main.go │ ├── pointer_to_pointer_incorrect │ └── main.go │ └── uintptr │ └── main.go └── lessons ├── allocator ├── allocation_1 │ └── main.go ├── allocation_2 │ └── main.go ├── allocation_3 │ └── main.go ├── allocation_4 │ └── main.go ├── allocation_5 │ └── main.go ├── allocation_effect_1 │ └── allocation_test.go ├── allocation_effect_2 │ └── allocation_test.go ├── allocation_effect_3 │ └── allocation_test.go ├── allocations_offset │ └── main.go ├── allocations_size │ └── main.go ├── arena_api │ └── main.go ├── arena_problem_1 │ └── main.go ├── arena_problem_2 │ └── main.go ├── arena_problem_3 │ └── main.go ├── big_allocations │ └── main.go ├── linear_allocator │ └── main.go ├── loop_allocations │ └── allocations_test.go ├── pool │ └── pool_test.go ├── pool_allocator │ └── main.go ├── stack_allocator │ └── main.go └── stack_growth │ └── main.go ├── channels ├── broadcast │ └── main.go ├── buffered_channel │ └── main.go ├── channel_data_race │ └── main.go ├── channel_interaction │ └── main.go ├── copy_channel │ └── main.go ├── deadlock │ └── main.go ├── goroutine_leak_1 │ └── main.go ├── goroutine_leak_2 │ └── main.go ├── increment_with_channel │ └── main.go ├── increment_with_mutex │ └── main.go ├── is_closed_1 │ └── main.go ├── is_closed_2 │ └── main.go ├── nil_channel │ └── main.go ├── nil_channel_task │ └── main.go ├── non_blocking_channels_correct │ └── main.go ├── non_blocking_channels_incorrect │ └── main.go ├── operations_with_channel │ └── main.go ├── prioritization │ └── main.go ├── prioritization_weight │ └── main.go ├── producer_consumer │ └── main.go ├── select │ └── main.go ├── select_forever │ └── main.go ├── select_with_break_and_continue │ └── main.go ├── select_with_main_goroutine │ └── main.go ├── sequential_execution │ └── main.go ├── signals │ └── main.go ├── unidirectional_channels │ └── main.go └── write_after_close │ └── main.go ├── contexts ├── after_done │ └── main.go ├── chech_cancel │ └── main.go ├── context_handling │ └── main.go ├── context_inheritance_1 │ └── main.go ├── context_inheritance_2 │ └── main.go ├── context_with_cancel │ └── main.go ├── context_with_cancel_cause │ └── main.go ├── context_with_http_client │ └── main.go ├── context_with_http_server │ └── main.go ├── context_with_timeout │ └── main.go ├── context_with_timeout_cause │ └── main.go ├── context_with_timeout_implementation │ └── main.go ├── context_with_value │ └── main.go ├── context_with_value_inheritance │ └── main.go ├── context_with_value_type │ └── main.go ├── context_without_cancel │ └── main.go ├── errgroup_with_ctx │ ├── go.mod │ ├── go.sum │ └── main.go ├── graceful_shutdown │ └── main.go ├── nil_context │ └── main.go └── with_ctx_check │ └── main.go ├── data_types ├── bit_mask │ └── main.go ├── bit_wrappers │ └── main.go ├── bitmap_index │ └── main.go ├── bool_mask │ └── main.go ├── conversion_test │ └── conversion_test.go ├── duplicate_check │ └── check_test.go ├── endianness │ └── main.go ├── endianness_check │ └── main.go ├── even_test │ └── even_test.go ├── find_unique │ └── main.go ├── int_overflow │ └── main.go ├── inversion │ └── main.go ├── ipv4_address │ └── main.go ├── octal_system │ └── main.go ├── overflow_detection │ └── main.go ├── pointer │ └── main.go ├── pointer_to_pointer_correct │ └── main.go ├── pointer_to_pointer_incorrect │ └── main.go ├── pointer_with_function │ └── main.go ├── power_of_two │ └── main.go ├── uintptr_gc │ └── main.go ├── uintptr_stack_grow │ └── main.go ├── unsafe_analysis │ └── main.go ├── unsafe_pointer │ └── main.go └── unsafe_size_of │ └── main.go ├── environment ├── init_in_any_files │ ├── main.go │ └── secondary.go ├── init_in_any_packages │ ├── main │ │ └── main.go │ └── secondary │ │ └── secondary.go ├── init_in_one_file │ └── main.go └── init_order │ └── main.go ├── errors ├── change_global_error │ └── main.go ├── constant_error │ └── main.go ├── division_by_zero │ └── main.go ├── division_by_zero_float │ └── main.go ├── errno │ └── main.go ├── error │ └── main.go ├── error_behavior │ └── main.go ├── error_flag │ └── main.go ├── error_from_defer │ └── main.go ├── error_new │ └── main.go ├── error_status │ └── main.go ├── error_with_stacktrace │ └── main.go ├── errorf │ └── main.go ├── errorf_with_packing │ └── main.go ├── errors_as │ └── main.go ├── errors_defer_ignoring │ └── main.go ├── errors_handling │ └── main.go ├── errors_ignoring │ └── main.go ├── errors_is │ └── main.go ├── errors_performance │ └── performance_test.go ├── errors_type_checking │ └── main.go ├── errors_value_checking │ └── main.go ├── incorrect_wrapping │ └── main.go ├── many_times_handling_1 │ └── main.go ├── many_times_handling_2 │ └── main.go ├── multierror │ └── main.go ├── nil_pointer_dereference │ └── main.go ├── oom │ └── main.go ├── optional │ └── main.go ├── os_exit │ └── main.go ├── panic │ └── main.go ├── panic_jump │ └── main.go ├── panic_nil │ └── main.go ├── panic_rethrow │ └── main.go ├── panic_task │ └── main.go ├── panic_with_defer_1 │ └── main.go ├── panic_with_defer_2 │ └── main.go ├── recover_without_defer │ └── main.go ├── replace_panic │ └── main.go ├── runtime_exit │ └── main.go ├── signal_errors │ └── main.go └── stack_overflow │ └── main.go ├── functions ├── composition │ └── main.go ├── continuation │ └── main.go ├── conveyor │ └── main.go ├── currying │ └── main.go ├── decorator │ └── main.go ├── defer_calculating │ └── main.go ├── defer_evaluation_moment │ └── main.go ├── defer_inactive │ └── main.go ├── defer_inside_loop │ └── main.go ├── defer_modification_1 │ └── main.go ├── defer_modification_2 │ └── main.go ├── defer_nil │ └── main.go ├── defer_order │ └── main.go ├── defer_performance │ └── comparison_test.go ├── defer_union │ └── main.go ├── defer_with_function │ └── main.go ├── filename_like_argument │ └── main.go ├── functions_inlining │ └── comparison_test.go ├── generator │ └── main.go ├── high_order_function │ └── main.go ├── imperative_declarative │ └── main.go ├── lazy_evaluation │ └── main.go ├── memoization │ └── main.go ├── named_return_values │ └── main.go ├── predicate │ └── main.go ├── pure_function │ └── main.go ├── random_generator │ └── main.go ├── recursion │ └── recursion_test.go ├── stack_overflow │ └── main.go └── variadic_parameters │ └── main.go ├── garbage_collector ├── add_cleanup │ └── main.go ├── big_allocations │ └── main.go ├── finalizers │ └── main.go ├── finalizers_any_times │ └── main.go ├── finalizers_cycle │ └── main.go ├── finalizers_not_first_word │ └── main.go ├── finalizers_resurrection │ └── main.go ├── finalizers_unsafe_type │ └── main.go ├── memory_ballast │ └── main.go ├── weak_map │ └── main.go └── weak_ptr │ └── main.go ├── generics_and_reflection ├── cloneable_mixin │ └── main.go ├── constraint_with_field_correct │ └── main.go ├── constraint_with_field_incorrect │ └── main.go ├── constraint_with_method │ └── main.go ├── constraints_1 │ └── main.go ├── constraints_2 │ └── main.go ├── constraints_intersection │ └── main.go ├── constraints_union │ └── main.go ├── generic_constraint │ └── main.go ├── generic_decorator │ └── main.go ├── generic_method_correct │ └── main.go ├── generic_method_incorrect │ └── main.go ├── generic_method_set │ └── main.go ├── generic_set │ └── main.go ├── generic_variadic_parameters │ └── main.go ├── generics_maps_and_slices │ └── main.go ├── generics_slices_and_strings │ └── main.go ├── generics_with_constants │ └── main.go ├── generics_with_pointers │ └── main.go ├── generics_with_unsafe │ └── main.go ├── map_keys │ └── main.go ├── max │ └── main.go ├── max_generic │ └── main.go ├── method_set_constraint │ └── main.go ├── partial_type_alias │ └── main.go ├── private_fields_1 │ └── main.go ├── private_fields_2 │ └── main.go ├── reflect_can_set │ └── main.go ├── reflect_channel │ └── main.go ├── reflect_comparable │ └── main.go ├── reflect_convertible │ └── main.go ├── reflect_creation │ └── main.go ├── reflect_dynamic_type │ └── main.go ├── reflect_elem │ └── main.go ├── reflect_function_call │ └── main.go ├── reflect_generic │ └── main.go ├── reflect_implements │ └── main.go ├── reflect_interface_method │ └── main.go ├── reflect_leak │ └── main.go ├── reflect_map │ └── main.go ├── reflect_nothing │ └── main.go ├── reflect_select │ └── main.go ├── reflect_struct │ └── main.go ├── reflect_struct_field_tags │ └── main.go ├── reflect_typeof_and_valueof │ └── main.go ├── reflect_with_big_type │ └── main.go ├── reflect_with_struct_fields │ └── main.go ├── reflect_with_type_definition │ └── main.go ├── type_aliases │ └── main.go ├── type_assertions │ └── main.go ├── type_inference │ └── main.go ├── type_parameter_embedding │ └── main.go ├── type_parameters_skipping │ └── main.go ├── universal_fabric │ └── main.go └── unnamed_types │ └── main.go ├── goroutines_and_scheduler ├── async_preemptible │ └── main.go ├── endless_loop │ └── main.go ├── gmp_model │ └── main.go ├── goroutine_index │ └── main.go ├── goroutines_number │ └── main.go ├── never_exit │ └── main.go ├── panic_from_other_goroutine │ └── main.go ├── runtime_exit │ └── main.go ├── tcp_server_with_panic │ └── main.go └── tcp_server_without_panic │ └── main.go ├── interfaces ├── call_interface_method │ └── main.go ├── compare_interfaces │ └── main.go ├── consumer_interface │ ├── entity │ │ └── client.go │ ├── service │ │ ├── client_updater.go │ │ └── message_sender.go │ └── storage │ │ ├── mysql │ │ └── storage.go │ │ └── redis │ │ └── storage.go ├── different_interfaces │ └── main.go ├── duck_typing │ └── main.go ├── duck_typing_problem │ └── main.go ├── empty_interface │ └── main.go ├── empty_interfaces_conversion │ └── main.go ├── empty_interfaces_use_case │ └── main.go ├── generic_tree │ └── main.go ├── incorrect_methods │ └── main.go ├── interface_allocation │ └── main.go ├── interface_assignment │ └── main.go ├── interface_cast │ └── main.go ├── interface_composition │ └── main.go ├── interface_composition_with_struct │ └── main.go ├── interface_copy │ └── main.go ├── interface_guard │ └── main.go ├── interface_implementation │ └── main.go ├── interface_internals │ └── main.go ├── interface_key_in_map │ └── main.go ├── interface_not_nil_1 │ └── main.go ├── interface_not_nil_2 │ └── main.go ├── interface_not_nil_3 │ └── main.go ├── interface_performance │ └── performance_test.go ├── interface_with_receiver │ └── main.go ├── interface_with_receiver_reason │ └── main.go ├── numbers_comparison │ └── main.go ├── polymorphism │ └── main.go ├── producer_interface │ ├── service │ │ ├── client_updater.go │ │ └── message_sender.go │ └── storage │ │ ├── client.go │ │ ├── mysql │ │ └── storage.go │ │ └── redis │ │ └── storage.go ├── slice_values_to_slice_interfaces │ └── main.go ├── static_and_dynamic_type │ └── main.go ├── type_assertion_1 │ └── main.go ├── type_assertion_2 │ └── main.go ├── type_assertion_3 │ └── main.go ├── type_switch_1 │ └── main.go └── type_switch_2 │ └── main.go ├── maps ├── big_map │ └── main.go ├── bucket_structure │ └── main.go ├── comparable_keys │ └── main.go ├── comparison │ └── comparison_test.go ├── delete_during_iteration │ └── main.go ├── element_value_address │ └── main.go ├── hash_function │ └── main.go ├── iteration_order │ └── main.go ├── map_clearing │ └── main.go ├── map_empty_assign │ └── main.go ├── map_internals │ └── main.go ├── map_operations │ └── main.go ├── map_performance │ └── performance_test.go ├── map_with_float │ └── main.go ├── map_with_function_1 │ └── main.go ├── map_with_function_2 │ └── main.go ├── mapaccess │ └── main.go ├── range_by_map │ └── main.go ├── reservation │ └── comparison_test.go ├── update_during_iteration │ └── main.go └── update_value │ └── main.go ├── slices_and_arrays ├── access_by_index │ └── main.go ├── append_implementation │ └── main.go ├── array_moving │ └── main.go ├── array_operations │ └── main.go ├── arrays_allocation_1 │ └── main.go ├── arrays_allocation_2 │ └── main.go ├── arrays_with_different_type │ └── main.go ├── bce_absence │ └── main.go ├── bce_optimization_1 │ └── bench_test.go ├── bce_optimization_2 │ └── bench_test.go ├── bce_optimization_3 │ └── main.go ├── bce_presence │ └── main.go ├── big_slice_correct │ └── main.go ├── big_slice_incorrect │ └── main.go ├── check_length │ └── main.go ├── clip │ └── main.go ├── collection_optimization │ └── main.go ├── copy_implementation │ └── main.go ├── copy_slice │ └── main.go ├── dangerous_append │ └── main.go ├── different_range_by_array │ └── main.go ├── dirty_slice │ └── creation_test.go ├── empty_and_nil_slices │ └── main.go ├── endless_range │ └── main.go ├── incorrect_range_by_array │ └── main.go ├── iteration_by_pointer_to_array │ └── main.go ├── iteration_optimization │ └── comparison_test.go ├── memclr │ └── clear_test.go ├── pointer_to_slice_element │ └── main.go ├── range_by_array_comparison │ └── comparison_test.go ├── range_task │ └── main.go ├── reader_comparison │ └── comparison_test.go ├── reservation │ └── reservation_test.go ├── resize_slice │ └── main.go ├── slice_clearing │ └── main.go ├── slice_increasing │ └── main.go ├── slice_of_slices │ └── main.go ├── slice_operations │ └── main.go ├── slice_type_transformation │ └── main.go ├── slice_with_function_1 │ └── main.go ├── slice_with_function_2 │ └── main.go ├── slices_allocation │ └── main.go ├── slices_comparison │ └── main.go ├── slices_comparison_effective │ └── comparison_test.go ├── slices_comparison_recursive │ └── main.go ├── slices_to_array_pointer │ └── main.go ├── slices_to_arrays │ └── main.go ├── slicing_operations │ └── main.go ├── slicing_task │ └── main.go └── without_bound_checks │ └── bench_test.go ├── strings ├── .DS_Store ├── allocations │ └── main.go ├── append_and_copy │ └── main.go ├── bce_optimization │ └── bench_test.go ├── byte_address │ └── main.go ├── byte_slice_to_string │ └── comparison_test.go ├── const_strings │ └── main.go ├── conversion_deprecated │ └── main.go ├── conversion_optimizations │ └── main.go ├── cow_string │ └── main.go ├── encodings │ └── main.go ├── interpreted_and_raw_strings │ └── main.go ├── leak_with_string │ └── main.go ├── letter_frequencies │ └── main.go ├── letter_order │ └── main.go ├── mutate_string_1 │ └── main.go ├── mutate_string_2 │ └── main.go ├── range_ascii_vs_utf8 │ └── speed_test.go ├── rune_to_bytes_test │ └── perf_test.go ├── runes_to_bytes │ └── main.go ├── speed_comparison │ └── comparison_test.go ├── speed_concatenation │ └── concatenation_test.go ├── string_builder │ └── speed_test.go ├── string_builder_copy │ └── main.go ├── string_builder_implementation │ └── main.go ├── string_implementation │ └── main.go ├── string_len │ └── main.go ├── string_to_byte_slice │ └── comparison_test.go ├── strings_operations │ └── main.go ├── strings_range │ └── main.go ├── substring │ └── main.go ├── trim_right_and_trim_suffix │ └── main.go └── unique │ └── bench_test.go ├── structs ├── alignment_functions │ └── main.go ├── ambiguous_selectors │ └── main.go ├── anonymous_struct │ └── main.go ├── bind_receiver │ └── main.go ├── blank_methods │ └── main.go ├── check_struct_size │ └── main.go ├── closer │ └── main.go ├── comparison │ └── main.go ├── comparison_benchmark │ └── comparison_test.go ├── configurable_object │ └── main.go ├── copy_struct │ └── main.go ├── defer_calculating_1 │ └── main.go ├── defer_calculating_2 │ └── main.go ├── different_receivers │ └── main.go ├── dod │ └── comparison_test.go ├── empty_struct_size │ └── main.go ├── empty_structs │ └── main.go ├── empty_structs_internal │ └── main.go ├── final_zero_field │ └── main.go ├── functional_options │ └── main.go ├── implicit_method_call │ └── main.go ├── inheritance │ └── main.go ├── methods_for_basic_types │ └── main.go ├── methods_with_types │ └── main.go ├── nil_receiver │ └── main.go ├── optional_parameters │ └── main.go ├── recursive_receiver │ └── main.go ├── skipping_selectors │ └── main.go ├── struct │ └── main.go ├── struct_alignment_1 │ └── main.go ├── struct_alignment_2 │ └── main.go ├── struct_inside_function │ └── main.go ├── stuct_sugar │ └── main.go ├── type_alias_and_definition │ └── main.go ├── type_alias_and_definition_with_method │ └── main.go ├── type_embedding_correct │ └── main.go ├── type_embedding_incorrect │ └── main.go ├── union_1 │ └── main.go ├── union_2 │ └── main.go └── unsafe_cast │ └── performance_test.go └── sync_primitives ├── action_during_actions └── main.go ├── atomic_performance └── perf_test.go ├── cas_loop └── main.go ├── compare_and_swap └── main.go ├── cond └── main.go ├── cond_operations └── main.go ├── correct_increment └── main.go ├── data_race └── main.go ├── deadlock └── main.go ├── deadlock_with_work └── main.go ├── defer_with_mutex └── main.go ├── defer_with_panic └── main.go ├── false_sharing └── perf_test.go ├── incorrect_buffer_design └── main.go ├── incorrect_increment └── main.go ├── incorrect_struct_design └── main.go ├── livelock └── main.go ├── local_mutex └── main.go ├── lock_granularity └── main.go ├── lockable_struct └── main.go ├── mutex_different_operations └── main.go ├── mutex_operations └── main.go ├── mutex_with_common_values └── main.go ├── mutex_with_local_values └── main.go ├── recursive_lock └── main.go ├── rlocker └── main.go ├── rw_mutex_operations └── main.go ├── rw_mutex_performance └── perf_test.go ├── rw_mutex_with_map └── main.go ├── semaphore └── main.go ├── starvation └── main.go ├── sync_stack └── main.go ├── wait_group_copying └── main.go ├── wait_group_operations └── main.go └── waiting_goroutines └── main.go /go.mod: -------------------------------------------------------------------------------- 1 | module golang_course 2 | 3 | go 1.22 4 | 5 | require ( 6 | github.com/stretchr/testify v1.9.0 7 | golang.org/x/text v0.18.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | gopkg.in/yaml.v3 v3.0.1 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /homework/errors/homework_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | // go test -v homework_test.go 11 | 12 | type MultiError struct { 13 | // need to implement 14 | } 15 | 16 | func (e *MultiError) Error() string { 17 | // need to implement 18 | return "" 19 | } 20 | 21 | func Append(err error, errs ...error) *MultiError { 22 | // need to implement 23 | return nil 24 | } 25 | 26 | func TestMultiError(t *testing.T) { 27 | var err error 28 | err = Append(err, errors.New("error 1")) 29 | err = Append(err, errors.New("error 2")) 30 | 31 | expectedMessage := "2 errors occured:\n\t* error 1\t* error 2\n" 32 | assert.EqualError(t, err, expectedMessage) 33 | } 34 | -------------------------------------------------------------------------------- /interviews/data_types/endianness/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | var number int32 = 0x12345678 10 | pointer := unsafe.Pointer(&number) 11 | 12 | fmt.Printf("0x") 13 | for i := 0; i < 4; i++ { 14 | byteValue := *(*int8)(unsafe.Add(pointer, i)) 15 | fmt.Printf("%x", byteValue) 16 | } 17 | 18 | fmt.Println() 19 | } 20 | -------------------------------------------------------------------------------- /interviews/data_types/endianness_check/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func IsLittleEndian() bool { 9 | var number int16 = 0x0001 10 | pointer := (*int8)(unsafe.Pointer(&number)) 11 | return *pointer == 1 12 | } 13 | 14 | func IsBigEndian() bool { 15 | return !IsLittleEndian() 16 | } 17 | 18 | func main() { 19 | if IsLittleEndian() { 20 | fmt.Println("Little endian") 21 | } else { 22 | fmt.Println("Big endian") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /interviews/data_types/int_overflow/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | func main() { 9 | var signed int8 = math.MaxInt8 10 | signed++ 11 | 12 | var unsigned uint8 = math.MaxUint8 13 | unsigned++ 14 | 15 | fmt.Println(signed) 16 | fmt.Println(unsigned) 17 | 18 | // var signed int8 = math.MaxInt8 + 1 -> compilation error 19 | // var unsigned uint8 = math.MaxUint8 + 1 -> compilation error 20 | } 21 | -------------------------------------------------------------------------------- /interviews/data_types/inversion/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var x uint8 = 3 7 | var y int8 = 3 8 | 9 | fmt.Println(^x) 10 | fmt.Println(^y) 11 | } 12 | -------------------------------------------------------------------------------- /interviews/data_types/octal_system/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | sum := 100 + 010 7 | fmt.Println(sum) 8 | } 9 | -------------------------------------------------------------------------------- /interviews/data_types/pointer_to_pointer_correct/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func process(temp **int32) { 6 | var value2 int32 = 200 7 | *temp = &value2 8 | } 9 | 10 | func main() { 11 | var value1 int32 = 100 12 | pointer := &value1 13 | 14 | fmt.Println(*pointer) 15 | fmt.Println(pointer) 16 | 17 | process(&pointer) 18 | 19 | fmt.Println(*pointer) 20 | fmt.Println(pointer) 21 | } 22 | -------------------------------------------------------------------------------- /interviews/data_types/pointer_to_pointer_incorrect/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func process(temp *int32) { 6 | var value2 int32 = 200 7 | temp = &value2 8 | } 9 | 10 | func main() { 11 | var value1 int32 = 100 12 | pointer := &value1 13 | 14 | fmt.Println(*pointer) 15 | fmt.Println(pointer) 16 | 17 | process(pointer) 18 | 19 | fmt.Println(*pointer) 20 | fmt.Println(pointer) 21 | } 22 | -------------------------------------------------------------------------------- /interviews/data_types/uintptr/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "runtime" 5 | "unsafe" 6 | ) 7 | 8 | // go run main.go 9 | // go run -gcflags=-d=checkptr main.go 10 | 11 | func main() { 12 | x := new(int) 13 | y := new(int) 14 | z := new(int) 15 | 16 | ptrX := unsafe.Pointer(x) 17 | ptrY := unsafe.Pointer(y) 18 | addressZ := uintptr(unsafe.Pointer(z)) 19 | 20 | // arithmetic operation 21 | _ = addressZ + 2 22 | _ = addressZ - 2 23 | 24 | runtime.GC() 25 | 26 | *(*int)(ptrX) = 100 27 | *(*int)(ptrY) = 200 28 | *(*int)(unsafe.Pointer(addressZ)) = 300 // dangerous 29 | } 30 | -------------------------------------------------------------------------------- /lessons/allocator/allocation_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // -l = disable inlining 4 | // -m = print optimization decisions 5 | // go build -gcflags '-l -m' 6 | 7 | func getResult() int { 8 | result := 200 9 | return result 10 | } 11 | 12 | func main() { 13 | _ = getResult() 14 | } 15 | -------------------------------------------------------------------------------- /lessons/allocator/allocation_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // -l = disable inlining 4 | // -m = print optimization decisions 5 | // go build -gcflags '-l -m' 6 | 7 | func getResult() *int { 8 | result := 200 9 | return &result 10 | } 11 | 12 | func main() { 13 | _ = getResult() 14 | } 15 | -------------------------------------------------------------------------------- /lessons/allocator/allocation_3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // -l = disable inlining 4 | // -m = print optimization decisions 5 | // go build -gcflags '-l -m' 6 | 7 | func getResult(number *int) int { 8 | result := *number + 200 9 | return result 10 | } 11 | 12 | func main() { 13 | number := 100 14 | _ = getResult(&number) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/allocator/allocation_4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // -l = disable inlining 6 | // -m = print optimization decisions 7 | // go build -gcflags '-l -m' 8 | 9 | func printValue(v interface{}) { 10 | fmt.Println(v) 11 | //_, _ = v.(int) 12 | } 13 | 14 | func main() { 15 | var num1 int = 10 16 | var str1 string = "Hello" 17 | 18 | printValue(num1) 19 | printValue(str1) 20 | 21 | var num2 int = 10 22 | var str2 string = "Hello" 23 | 24 | var i interface{} 25 | i = num2 26 | i = str2 27 | _ = i 28 | } 29 | -------------------------------------------------------------------------------- /lessons/allocator/allocation_5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // -l = disable inlining 4 | // -m = print optimization decisions 5 | // go build -gcflags '-l -m' 6 | 7 | func createPointer() *int { 8 | value2 := new(int) 9 | return value2 10 | } 11 | 12 | func main() { 13 | value1 := new(int) // stack 14 | _ = value1 15 | 16 | value2 := createPointer() // heap 17 | _ = value2 18 | } 19 | -------------------------------------------------------------------------------- /lessons/allocator/allocation_effect_1/allocation_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | // go test -bench=. -benchmem 6 | 7 | type Data struct { 8 | iValue int 9 | sValue string 10 | bValue bool 11 | } 12 | 13 | //go:noinline 14 | func NewDataByValue() Data { 15 | return Data{iValue: 100, sValue: "100", bValue: true} 16 | } 17 | 18 | //go:noinline 19 | func NewDataByPointer() *Data { 20 | return &Data{iValue: 100, sValue: "100", bValue: true} 21 | } 22 | 23 | func BenchmarkNewByValue(b *testing.B) { 24 | for i := 0; i < b.N; i++ { 25 | _ = NewDataByValue() 26 | } 27 | } 28 | 29 | func BenchmarkNewByPointer(b *testing.B) { 30 | for i := 0; i < b.N; i++ { 31 | _ = NewDataByPointer() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lessons/allocator/allocation_effect_3/allocation_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | // go test -bench=. -benchmem 6 | 7 | type Data struct { 8 | pointer *int 9 | } 10 | 11 | func BenchmarkIteration1(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | var number int 14 | data := &Data{ 15 | pointer: &number, 16 | } 17 | _ = data 18 | } 19 | } 20 | 21 | func BenchmarkIteration2(b *testing.B) { 22 | for i := 0; i < b.N; i++ { 23 | var number int 24 | data := &Data{} 25 | data.pointer = &number 26 | _ = data 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lessons/allocator/allocations_size/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | var result string 9 | var buffer []byte = make([]byte, 33) 10 | 11 | func Concat(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | result = string(buffer) + string(buffer) 14 | } 15 | } 16 | 17 | func main() { 18 | b := testing.Benchmark(Concat) 19 | fmt.Println(b.AllocsPerOp()) // 3 20 | fmt.Println(b.AllocedBytesPerOp()) // 176 21 | 22 | // alocated 176 bytes = 48 (not 33) + 48 (not 33) + 80 (not 33 + 33 = 66) 23 | // waste = 15 + 15 + 14 = 44 bytes (25% waste) 24 | } 25 | -------------------------------------------------------------------------------- /lessons/allocator/arena_api/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // GOEXPERIMENT=arenas go run main.go 4 | // go run -tags goexperiment.arenas main.go 5 | 6 | import ( 7 | "arena" 8 | ) 9 | 10 | type Data struct { 11 | deposit int 12 | credit int 13 | } 14 | 15 | func main() { 16 | a := arena.NewArena() 17 | defer a.Free() 18 | 19 | value := arena.New[int64](a) 20 | _ = value 21 | 22 | data := arena.New[Data](a) 23 | _ = data 24 | 25 | slice := arena.MakeSlice[int32](a, 0, 10) 26 | _ = slice 27 | 28 | cloned := arena.Clone[*Data](data) // moved to heap 29 | _ = cloned 30 | } 31 | -------------------------------------------------------------------------------- /lessons/allocator/arena_problem_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // GOEXPERIMENT=arenas go run main.go 4 | // go run -tags goexperiment.arenas main.go 5 | 6 | import ( 7 | "arena" 8 | ) 9 | 10 | type Data struct { 11 | value int 12 | operaions []int 13 | } 14 | 15 | func main() { 16 | a := arena.NewArena() 17 | defer a.Free() 18 | 19 | // Arenas will not allocate all reference types automatically 20 | operations := arena.MakeSlice[int](a, 0, 100) 21 | data := arena.New[Data](a) 22 | data.operaions = operations 23 | _ = data 24 | } 25 | -------------------------------------------------------------------------------- /lessons/allocator/arena_problem_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // GOEXPERIMENT=arenas go run main.go 4 | // go run -tags goexperiment.arenas main.go 5 | 6 | import ( 7 | "arena" 8 | ) 9 | 10 | func main() { 11 | mem := arena.NewArena() 12 | defer mem.Free() 13 | 14 | slice := arena.NewSlice[int](mem, 0, 5) 15 | slice = append(slice, 1, 2, 3, 4, 5) 16 | 17 | slice = append(slice, 6) // moved to heap 18 | } 19 | -------------------------------------------------------------------------------- /lessons/allocator/arena_problem_3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // GOEXPERIMENT=arenas go run main.go 4 | // go run -tags goexperiment.arenas main.go 5 | 6 | import ( 7 | "arena" 8 | "fmt" 9 | ) 10 | 11 | type Data struct { 12 | deposit int 13 | credit int 14 | } 15 | 16 | func main() { 17 | a := arena.NewArena() 18 | data := arena.New[Data](a) 19 | a.Free() 20 | 21 | // use after free 22 | fmt.Println(data) 23 | } 24 | -------------------------------------------------------------------------------- /lessons/allocator/big_allocations/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // go run main.go 6 | // GOGC=off go run main.go 7 | 8 | var data []byte 9 | 10 | func main() { 11 | count := 0 12 | 13 | for { 14 | data = make([]byte, 1<<30) 15 | /*for idx := 0; idx < 1<<30; idx += 4096 { 16 | data[idx] = 100 17 | }*/ 18 | 19 | fmt.Println("allocated GB:", count) 20 | count++ 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lessons/allocator/loop_allocations/allocations_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // go test -bench=. allocations_test.go -benchmem 4 | 5 | import ( 6 | "testing" 7 | ) 8 | 9 | //go:noinline 10 | func Initialize(value *int) { 11 | *value = 1000 12 | } 13 | 14 | func BenchmarkWithoutLoopAllocation(b *testing.B) { 15 | var value int 16 | for i := 0; i < b.N; i++ { 17 | Initialize(&value) 18 | } 19 | } 20 | 21 | func BenchmarkWithLoopAllocation(b *testing.B) { 22 | for i := 0; i < b.N; i++ { 23 | var value int 24 | Initialize(&value) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lessons/allocator/stack_growth/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // -l = disable inlining 4 | // -m = print optimization decisions 5 | // go build -gcflags '-l -m' 6 | // go run -gcflags '-l' main.go 7 | 8 | func process(index int) byte { 9 | var data [1 << 20]byte 10 | return data[index] 11 | } 12 | 13 | func main() { 14 | var index int = 100 15 | 16 | pointer := &index 17 | println("pointer:", pointer) 18 | process(index) 19 | println("pointer:", pointer) 20 | } 21 | -------------------------------------------------------------------------------- /lessons/channels/broadcast/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func notifier(signals chan int) { 9 | close(signals) 10 | } 11 | 12 | func subscriber(signals chan int) { 13 | <-signals 14 | fmt.Println("signaled") 15 | } 16 | 17 | func main() { 18 | signals := make(chan int) 19 | wg := sync.WaitGroup{} 20 | wg.Add(3) 21 | 22 | go func() { 23 | defer wg.Done() 24 | notifier(signals) 25 | }() 26 | 27 | go func() { 28 | defer wg.Done() 29 | subscriber(signals) 30 | }() 31 | 32 | go func() { 33 | defer wg.Done() 34 | subscriber(signals) 35 | }() 36 | 37 | wg.Wait() 38 | } 39 | -------------------------------------------------------------------------------- /lessons/channels/buffered_channel/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | ch := make(chan int, 2) 5 | ch <- 100 6 | ch <- 100 7 | } 8 | -------------------------------------------------------------------------------- /lessons/channels/channel_data_race/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | // go run -race main.go 6 | 7 | var buffer chan int 8 | 9 | func main() { 10 | wg := sync.WaitGroup{} 11 | wg.Add(100) 12 | 13 | for i := 0; i < 100; i++ { 14 | go func() { 15 | defer wg.Done() 16 | buffer = make(chan int) 17 | }() 18 | } 19 | 20 | wg.Wait() 21 | } 22 | -------------------------------------------------------------------------------- /lessons/channels/channel_interaction/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // Describe blocking 9 | 10 | func async(ch chan string) { 11 | time.Sleep(2 * time.Second) 12 | ch <- "async result" 13 | } 14 | 15 | func main() { 16 | ch := make(chan string) 17 | go async(ch) 18 | // ... 19 | result := <-ch 20 | fmt.Println(result) 21 | } 22 | -------------------------------------------------------------------------------- /lessons/channels/copy_channel/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | source := make(chan int) 7 | clone := source 8 | 9 | go func() { 10 | source <- 1 11 | }() 12 | 13 | fmt.Println(<-clone) 14 | } 15 | -------------------------------------------------------------------------------- /lessons/channels/goroutine_leak_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | doWork := func(strings <-chan string) { 11 | go func() { 12 | for str := range strings { 13 | fmt.Println(str) 14 | } 15 | 16 | log.Println("doWork exited") 17 | }() 18 | } 19 | 20 | strings := make(chan string) 21 | doWork(strings) 22 | strings <- "Test" 23 | 24 | time.Sleep(time.Second) 25 | fmt.Println("Done") 26 | } 27 | -------------------------------------------------------------------------------- /lessons/channels/goroutine_leak_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Need to show solution and describe close 4 | 5 | // First-response-wins strategy 6 | func request() int { 7 | ch := make(chan int) 8 | for i := 0; i < 5; i++ { 9 | go func() { 10 | ch <- i // 4 goroutines will be blocked 11 | }() 12 | } 13 | 14 | return <-ch 15 | } 16 | -------------------------------------------------------------------------------- /lessons/channels/increment_with_channel/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | ch := make(chan int) 9 | 10 | go func() { 11 | ch <- 1 12 | }() 13 | go func() { 14 | ch <- 1 15 | }() 16 | 17 | value := 0 18 | value += <-ch 19 | value += <-ch 20 | 21 | fmt.Println(value) 22 | } 23 | -------------------------------------------------------------------------------- /lessons/channels/increment_with_mutex/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func main() { 9 | mutex := sync.Mutex{} 10 | wg := sync.WaitGroup{} 11 | wg.Add(2) 12 | 13 | value := 0 14 | for i := 0; i < 2; i++ { 15 | go func() { 16 | defer wg.Done() 17 | 18 | mutex.Lock() 19 | value++ 20 | mutex.Unlock() 21 | }() 22 | } 23 | 24 | wg.Wait() 25 | 26 | fmt.Println(value) 27 | } 28 | -------------------------------------------------------------------------------- /lessons/channels/is_closed_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func IsClosed(ch chan int) bool { 6 | select { 7 | case <-ch: 8 | return true 9 | default: 10 | return false 11 | } 12 | } 13 | 14 | func main() { 15 | ch := make(chan int) 16 | fmt.Println(IsClosed(ch)) 17 | close(ch) 18 | fmt.Println(IsClosed(ch)) 19 | } 20 | -------------------------------------------------------------------------------- /lessons/channels/is_closed_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Need to show solution 6 | 7 | func IsClosed(ch chan int) bool { 8 | select { 9 | case <-ch: 10 | return true 11 | default: 12 | return false 13 | } 14 | } 15 | 16 | func main() { 17 | ch := make(chan int, 1) 18 | ch <- 1 19 | fmt.Println(IsClosed(ch)) 20 | close(ch) 21 | fmt.Println(IsClosed(ch)) 22 | } 23 | -------------------------------------------------------------------------------- /lessons/channels/nil_channel_task/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | ch := make(chan int, 1) 7 | for done := false; !done; { 8 | select { 9 | default: 10 | fmt.Println(3) 11 | done = true 12 | case <-ch: 13 | fmt.Println(2) 14 | ch = nil 15 | case ch <- 1: 16 | fmt.Println(1) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lessons/channels/non_blocking_channels_correct/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func tryToReadFromChannel(ch chan string) (string, bool) { 4 | select { 5 | case value := <-ch: 6 | return value, true 7 | default: 8 | return "", false 9 | } 10 | } 11 | 12 | func tryToWriteToChannel(ch chan string, value string) bool { 13 | select { 14 | case ch <- value: 15 | return true 16 | default: 17 | return false 18 | } 19 | } 20 | 21 | func tryToReadOrWrite(ch1 chan string, ch2 chan string) { 22 | select { 23 | case <-ch1: 24 | case ch2 <- "test": 25 | default: 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lessons/channels/non_blocking_channels_incorrect/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func tryToReadFromChannel(ch chan string) (string, bool) { 4 | if len(ch) != 0 { 5 | value := <-ch 6 | return value, true 7 | } else { 8 | return "", false 9 | } 10 | } 11 | 12 | func tryToWriteToChannel(ch chan string, value string) bool { 13 | if len(ch) < cap(ch) { 14 | ch <- value 15 | return true 16 | } else { 17 | return false 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lessons/channels/prioritization/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // Need to show solution 9 | 10 | func producer(ch chan<- int) { 11 | for { 12 | ch <- 1 13 | time.Sleep(time.Second) 14 | } 15 | } 16 | 17 | func main() { 18 | ch1 := make(chan int) // more prioritized 19 | ch2 := make(chan int) 20 | 21 | go producer(ch1) 22 | go producer(ch2) 23 | 24 | for { 25 | select { 26 | case value := <-ch1: 27 | fmt.Println(value) 28 | return 29 | case value := <-ch2: 30 | fmt.Println(value) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lessons/channels/prioritization_weight/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | ch1 := make(chan struct{}, 1) 7 | ch2 := make(chan struct{}, 1) 8 | 9 | close(ch1) 10 | close(ch2) 11 | 12 | ch1Value := 0.0 13 | ch2Value := 0.0 14 | 15 | for i := 0; i < 100000; i++ { 16 | select { 17 | case <-ch1: 18 | ch1Value++ 19 | case <-ch1: 20 | ch1Value++ 21 | case <-ch2: 22 | ch2Value++ 23 | } 24 | } 25 | 26 | fmt.Println(ch1Value / ch2Value) 27 | } 28 | -------------------------------------------------------------------------------- /lessons/channels/select/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func async1() chan string { 9 | ch := make(chan string) 10 | go func() { 11 | time.Sleep(1 * time.Second) 12 | ch <- "async1 result" 13 | }() 14 | return ch 15 | } 16 | 17 | func async2() chan string { 18 | ch := make(chan string) 19 | go func() { 20 | time.Sleep(1 * time.Second) 21 | ch <- "async2 result" 22 | }() 23 | return ch 24 | } 25 | 26 | func main() { 27 | ch1 := async1() 28 | ch2 := async2() 29 | 30 | select { 31 | case result := <-ch1: 32 | fmt.Println(result) 33 | case result := <-ch2: 34 | fmt.Println(result) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lessons/channels/select_forever/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func way1() { 4 | make(chan struct{}) <- struct{}{} 5 | // or 6 | make(chan<- struct{}) <- struct{}{} 7 | } 8 | 9 | func way2() { 10 | <-make(chan struct{}) 11 | // or 12 | <-make(<-chan struct{}) 13 | // or 14 | for range make(<-chan struct{}) { 15 | } 16 | } 17 | 18 | func way3() { 19 | chan struct{}(nil) <- struct{}{} 20 | // or 21 | <-chan struct{}(nil) 22 | // or 23 | for range chan struct{}(nil) { 24 | } 25 | } 26 | 27 | func way4() { 28 | select {} 29 | } 30 | -------------------------------------------------------------------------------- /lessons/channels/select_with_break_and_continue/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | data := make(chan int) 7 | go func() { 8 | for i := 1; i <= 4; i++ { 9 | data <- i 10 | } 11 | close(data) 12 | }() 13 | 14 | for { 15 | value := 0 16 | opened := true 17 | 18 | select { 19 | case value, opened = <-data: 20 | if value == 2 { 21 | continue 22 | } else if value == 3 { 23 | break 24 | } 25 | 26 | if !opened { 27 | return 28 | } 29 | } 30 | 31 | fmt.Println(value) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lessons/channels/select_with_main_goroutine/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "runtime" 4 | 5 | func doSomething() { 6 | for { 7 | runtime.Gosched() 8 | } 9 | } 10 | 11 | func main() { 12 | go doSomething() 13 | go doSomething() 14 | select {} 15 | } 16 | -------------------------------------------------------------------------------- /lessons/channels/sequential_execution/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // Need to show solution 9 | 10 | func FetchData1() chan int { 11 | ch := make(chan int) 12 | go func() { 13 | time.Sleep(time.Second * 2) 14 | ch <- 10 15 | }() 16 | 17 | return ch 18 | } 19 | 20 | func FetchData2() chan int { 21 | ch := make(chan int) 22 | go func() { 23 | time.Sleep(time.Second * 2) 24 | ch <- 20 25 | }() 26 | 27 | return ch 28 | } 29 | 30 | func Process(value1, value2 int) { 31 | // Processing... 32 | } 33 | 34 | func main() { 35 | start := time.Now() 36 | Process(<-FetchData1(), <-FetchData2()) 37 | fmt.Println(time.Now().Sub(start)) 38 | } 39 | -------------------------------------------------------------------------------- /lessons/channels/signals/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func notifier(signals chan struct{}) { 9 | signals <- struct{}{} 10 | } 11 | 12 | func subscriber(signals chan struct{}) { 13 | <-signals 14 | fmt.Println("signaled") 15 | } 16 | 17 | func main() { 18 | signals := make(chan struct{}) 19 | wg := sync.WaitGroup{} 20 | wg.Add(2) 21 | 22 | go func() { 23 | defer wg.Done() 24 | notifier(signals) 25 | }() 26 | 27 | go func() { 28 | defer wg.Done() 29 | subscriber(signals) 30 | }() 31 | 32 | wg.Wait() 33 | } 34 | -------------------------------------------------------------------------------- /lessons/channels/unidirectional_channels/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func in(in chan<- int) { 6 | in <- 100 7 | close(in) 8 | } 9 | 10 | func out(out <-chan int) { 11 | fmt.Println(<-out) 12 | } 13 | 14 | func main() { 15 | var ch = make(chan int, 1) 16 | 17 | in(ch) 18 | out(ch) 19 | } 20 | -------------------------------------------------------------------------------- /lessons/channels/write_after_close/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | func main() { 8 | ch := make(chan int) 9 | go func() { 10 | ch <- 1 11 | }() 12 | 13 | time.Sleep(500 * time.Millisecond) 14 | 15 | close(ch) 16 | <-ch 17 | 18 | time.Sleep(100 * time.Millisecond) 19 | } 20 | -------------------------------------------------------------------------------- /lessons/contexts/after_done/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | // context.AfterFunc 10 | 11 | func WithCtxAfterFunc(ctx context.Context, action func()) { 12 | if action != nil { 13 | go func() { 14 | <-ctx.Done() 15 | action() 16 | }() 17 | } 18 | } 19 | 20 | func main() { 21 | ctx, cancel := context.WithCancel(context.Background()) 22 | WithCtxAfterFunc(ctx, func() { 23 | fmt.Println("after") 24 | }) 25 | 26 | cancel() 27 | 28 | time.Sleep(100 * time.Millisecond) 29 | } 30 | -------------------------------------------------------------------------------- /lessons/contexts/chech_cancel/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "context" 4 | 5 | func incorrectCheck(ctx context.Context, stream <-chan string) { 6 | data := <-stream 7 | _ = data 8 | } 9 | 10 | func correctCheck(ctx context.Context, stream <-chan string) { 11 | select { 12 | case data := <-stream: 13 | _ = data 14 | case <-ctx.Done(): 15 | return 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lessons/contexts/context_handling/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "time" 6 | ) 7 | 8 | func Query(string) string 9 | 10 | func DoQeury(qyeryStr string) (string, error) { 11 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) 12 | defer cancel() 13 | 14 | var resultCh chan string 15 | go func() { 16 | result := Query(qyeryStr) 17 | resultCh <- result 18 | }() 19 | 20 | select { 21 | case <-ctx.Done(): 22 | return "", ctx.Err() 23 | case result := <-resultCh: 24 | return result, nil 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lessons/contexts/context_inheritance_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) 11 | defer cancel() 12 | 13 | makeRequest(ctx) 14 | } 15 | 16 | func makeRequest(ctx context.Context) { 17 | timer := time.NewTimer(5 * time.Second) 18 | defer timer.Stop() 19 | 20 | newCtx, cancel := context.WithTimeout(ctx, 10*time.Second) 21 | defer cancel() 22 | 23 | select { 24 | case <-newCtx.Done(): 25 | fmt.Println("canceled") 26 | case <-timer.C: 27 | fmt.Println("timer") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lessons/contexts/context_inheritance_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 11 | defer cancel() 12 | 13 | _, cancel = context.WithCancel(ctx) 14 | cancel() 15 | 16 | if ctx.Err() != nil { 17 | fmt.Println("canceled") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lessons/contexts/context_with_cancel_cause/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | ) 8 | 9 | func main() { 10 | ctx, cancel := context.WithCancelCause(context.Background()) 11 | cancel(errors.New("error")) 12 | 13 | fmt.Println(ctx.Err()) 14 | fmt.Println(context.Cause(ctx)) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/contexts/context_with_http_client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond) 12 | defer cancel() 13 | 14 | req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://example.com", nil) 15 | if err != nil { 16 | fmt.Println(err.Error()) 17 | } 18 | 19 | if _, err = http.DefaultClient.Do(req); err != nil { 20 | fmt.Println(err.Error()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lessons/contexts/context_with_timeout/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func makeRequest(ctx context.Context) { 10 | timer := time.NewTimer(5 * time.Second) 11 | defer timer.Stop() 12 | 13 | select { 14 | case <-timer.C: 15 | fmt.Println("finished") 16 | case <-ctx.Done(): 17 | fmt.Println("canceled") 18 | } 19 | } 20 | 21 | func main() { 22 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) 23 | defer cancel() 24 | 25 | makeRequest(ctx) 26 | } 27 | -------------------------------------------------------------------------------- /lessons/contexts/context_with_timeout_cause/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | ctx, cancel := context.WithTimeoutCause(context.Background(), time.Second, errors.New("timeout")) 12 | defer cancel() // show difference 13 | 14 | <-ctx.Done() 15 | 16 | fmt.Println(ctx.Err()) 17 | fmt.Println(context.Cause(ctx)) 18 | } 19 | -------------------------------------------------------------------------------- /lessons/contexts/context_with_value/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | traceCtx := context.WithValue(context.Background(), "trace_id", "12-21-33") 10 | makeRequest(traceCtx) 11 | 12 | oldValue, ok := traceCtx.Value("trace_id").(string) 13 | if ok { 14 | fmt.Println("mainValue", oldValue) 15 | } 16 | } 17 | 18 | func makeRequest(ctx context.Context) { 19 | oldValue, ok := ctx.Value("trace_id").(string) 20 | if ok { 21 | fmt.Println("oldValue", oldValue) 22 | } 23 | 24 | newCtx := context.WithValue(ctx, "trace_id", "22-22-22") 25 | newValue, ok := newCtx.Value("trace_id").(string) 26 | if ok { 27 | fmt.Println("newValue", newValue) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lessons/contexts/context_with_value_inheritance/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | traceCtx := context.WithValue(context.Background(), "trace_id", "12-21-33") 10 | makeRequest(traceCtx) 11 | } 12 | 13 | func makeRequest(ctx context.Context) { 14 | oldValue, ok := ctx.Value("trace_id").(string) 15 | if ok { 16 | fmt.Println(oldValue) 17 | } 18 | 19 | newCtx, cancel := context.WithCancel(ctx) 20 | defer cancel() 21 | 22 | newValue, ok := newCtx.Value("trace_id").(string) 23 | if ok { 24 | fmt.Println(newValue) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lessons/contexts/context_without_cancel/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 11 | innerCtx := context.WithoutCancel(ctx) 12 | cancel() 13 | 14 | if innerCtx.Err() != nil { 15 | fmt.Println("canceled") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lessons/contexts/errgroup_with_ctx/go.mod: -------------------------------------------------------------------------------- 1 | module errgroup 2 | 3 | go 1.20 4 | 5 | require golang.org/x/sync v0.6.0 6 | -------------------------------------------------------------------------------- /lessons/contexts/errgroup_with_ctx/go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= 2 | golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 3 | -------------------------------------------------------------------------------- /lessons/contexts/nil_context/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | func process(ctx context.Context) { 8 | if ctx.Err() != nil { 9 | // handling... 10 | } 11 | } 12 | 13 | func main() { 14 | process(nil) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/contexts/with_ctx_check/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "context" 4 | 5 | func WithContexCheck(ctx context.Context, action func()) { 6 | if action == nil || ctx.Err() != nil { 7 | return 8 | } 9 | 10 | action() 11 | } 12 | 13 | func main() { 14 | ctx := context.Background() 15 | WithContexCheck(ctx, func() { 16 | // do something 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /lessons/data_types/bit_wrappers/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func IsSetBit(number, index int) bool { 4 | return (number & (1 << index)) != 0 5 | } 6 | 7 | func SetBit(number, index int) int { 8 | return number | (1 << index) 9 | } 10 | 11 | func InverseBit(number, index int) int { 12 | return number ^ (1 << index) 13 | } 14 | 15 | func ResetBit(number, index int) int { 16 | return number & ^(1 << index) 17 | } 18 | -------------------------------------------------------------------------------- /lessons/data_types/bitmap_index/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // 0000 0001 -> есть кальяны 4 | // 0000 0010 -> можно с животными 5 | // 0000 0100 -> есть виранда 6 | // 0000 1000 -> есть алкоголь 7 | // 0001 0000 -> есть живая музыка 8 | 9 | func searchRestaurants(pattern int8, bitmaps []int8) []int { 10 | var indexes []int 11 | for idx, bitmap := range bitmaps { 12 | if bitmap^pattern == 0 { 13 | indexes = append(indexes, idx) 14 | } 15 | } 16 | 17 | return indexes 18 | } 19 | 20 | func main() { 21 | restaurants := []int8{ 22 | 0b00001101, 23 | 0b00000010, 24 | 0b00010000, 25 | 0b00011111, 26 | 0b00001001, 27 | } 28 | 29 | pattern := int8(0b00011000) 30 | indexes := searchRestaurants(pattern, restaurants) 31 | _ = indexes 32 | } 33 | -------------------------------------------------------------------------------- /lessons/data_types/conversion_test/conversion_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | ) 7 | 8 | // go test -bench=. conversion_test.go 9 | 10 | var result int 11 | 12 | func BenchmarkConversion1(b *testing.B) { 13 | for i := 0; i < b.N; i++ { 14 | result = 10 << 20 15 | _ = result 16 | } 17 | } 18 | 19 | func BenchmarkConversion2(b *testing.B) { 20 | for i := 0; i < b.N; i++ { 21 | result = 10 * 1024 * 1024 22 | _ = result 23 | } 24 | } 25 | 26 | func BenchmarkConversion3(b *testing.B) { 27 | for i := 0; i < b.N; i++ { 28 | result = 10 * (int)(math.Pow(2, 20)) 29 | _ = result 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lessons/data_types/endianness/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | var number int32 = 0x12345678 10 | pointer := unsafe.Pointer(&number) 11 | 12 | fmt.Printf("0x") 13 | for i := 0; i < 4; i++ { 14 | byteValue := *(*int8)(unsafe.Add(pointer, i)) 15 | fmt.Printf("%x", byteValue) 16 | } 17 | 18 | fmt.Println() 19 | } 20 | -------------------------------------------------------------------------------- /lessons/data_types/endianness_check/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func IsLittleEndian() bool { 9 | var number int16 = 0x0001 10 | pointer := (*int8)(unsafe.Pointer(&number)) 11 | return *pointer == 1 12 | } 13 | 14 | func IsBigEndian() bool { 15 | return !IsLittleEndian() 16 | } 17 | 18 | func main() { 19 | if IsLittleEndian() { 20 | fmt.Println("Little endian") 21 | } else { 22 | fmt.Println("Big endian") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lessons/data_types/even_test/even_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // go test -bench=. even_test.go 8 | 9 | var result int 10 | 11 | func BenchmarkEven1(b *testing.B) { 12 | for i := 1; i < b.N; i++ { 13 | result = i & 1 14 | _ = result 15 | } 16 | } 17 | 18 | func BenchmarkEven2(b *testing.B) { 19 | for i := 1; i < b.N; i++ { 20 | result = i % 2 21 | _ = result 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lessons/data_types/find_unique/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var array = [...]int8{2, 3, 4, 2, 3, 1, 4} 7 | 8 | var number int8 9 | for _, element := range array { 10 | fmt.Printf("%08b ^ %08b = %08b\n", number, element, number^element) 11 | number ^= element 12 | } 13 | 14 | fmt.Printf("\nResult: %08b\n", number) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/data_types/int_overflow/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | func main() { 9 | var signed int8 = math.MaxInt8 10 | signed++ 11 | 12 | var unsigned uint8 = math.MaxUint8 13 | unsigned++ 14 | 15 | fmt.Println(signed) 16 | fmt.Println(unsigned) 17 | 18 | // var signed int8 = math.MaxInt8 + 1 -> compilation error 19 | // var unsigned uint8 = math.MaxUint8 + 1 -> compilation error 20 | } 21 | -------------------------------------------------------------------------------- /lessons/data_types/inversion/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var x uint8 = 3 7 | var y int8 = 3 8 | 9 | fmt.Println(^x) 10 | fmt.Println(^y) 11 | } 12 | -------------------------------------------------------------------------------- /lessons/data_types/octal_system/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | sum := 100 + 010 7 | fmt.Println(sum) 8 | } 9 | -------------------------------------------------------------------------------- /lessons/data_types/pointer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var value int32 = 100 7 | var pointer *int32 = &value 8 | 9 | fmt.Println("address:", pointer) 10 | fmt.Println("value:", *pointer) 11 | 12 | *pointer = 500 13 | 14 | fmt.Println("address:", pointer) 15 | fmt.Println("value:", *pointer) 16 | } 17 | -------------------------------------------------------------------------------- /lessons/data_types/pointer_to_pointer_correct/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func process(temp **int32) { 6 | var value2 int32 = 200 7 | *temp = &value2 8 | } 9 | 10 | func main() { 11 | var value1 int32 = 100 12 | pointer := &value1 13 | 14 | fmt.Println("value:", *pointer) 15 | fmt.Println("address:", pointer) 16 | 17 | process(&pointer) 18 | 19 | fmt.Println("value", *pointer) 20 | fmt.Println("address:", pointer) 21 | } 22 | -------------------------------------------------------------------------------- /lessons/data_types/pointer_to_pointer_incorrect/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func process(temp *int32) { 6 | var value2 int32 = 200 7 | temp = &value2 8 | } 9 | 10 | func main() { 11 | var value1 int32 = 100 12 | pointer := &value1 13 | 14 | fmt.Println("value:", *pointer) 15 | fmt.Println("adress:", pointer) 16 | 17 | process(pointer) 18 | 19 | fmt.Println("value:", *pointer) 20 | fmt.Println("adress:", pointer) 21 | } 22 | -------------------------------------------------------------------------------- /lessons/data_types/pointer_with_function/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Need to show solution 6 | 7 | func double(number int) { 8 | fmt.Println("address:", &number) 9 | number *= 2 10 | } 11 | 12 | func main() { 13 | number := 100 14 | double(number) 15 | fmt.Println("number: ", number) 16 | fmt.Println("address:", &number) 17 | } 18 | -------------------------------------------------------------------------------- /lessons/data_types/power_of_two/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // 0000 0000 = 0 4 | // 0000 0001 = 1 5 | // 0000 0010 = 2 6 | // 0000 0100 = 4 7 | // 0000 1000 = 8 8 | // 0001 0000 = 16 9 | // 0010 0000 = 32 10 | // 0100 0000 = 64 11 | // 1000 0000 = 128 12 | 13 | // 0000 1111 14 | 15 | func IsPowerOfTwo(value int) bool { 16 | return value > 0 && value&(value-1) == 0 17 | } 18 | -------------------------------------------------------------------------------- /lessons/data_types/uintptr_gc/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "runtime" 5 | "unsafe" 6 | ) 7 | 8 | // go run main.go 9 | // go run -gcflags=-d=checkptr main.go 10 | 11 | func main() { 12 | x := new(int) 13 | y := new(int) 14 | 15 | ptrX := unsafe.Pointer(x) 16 | addressY := uintptr(unsafe.Pointer(y)) 17 | 18 | // arithmetic operation 19 | _ = addressY + 2 20 | _ = addressY - 2 21 | 22 | runtime.GC() 23 | 24 | *(*int)(ptrX) = 100 25 | *(*int)(unsafe.Pointer(addressY)) = 300 // dangerous 26 | } 27 | -------------------------------------------------------------------------------- /lessons/data_types/uintptr_stack_grow/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | // go run main.go 9 | // go run -gcflags=-d=checkptr main.go 10 | 11 | //go:noinline 12 | func allocation(index int) byte { 13 | var data [1 << 20]byte 14 | return data[index] 15 | } 16 | 17 | func main() { 18 | var array [10]int 19 | address1 := (uintptr)(unsafe.Pointer(&array)) 20 | fmt.Println("address1:", address1) 21 | 22 | allocation(100) 23 | 24 | address2 := (uintptr)(unsafe.Pointer(&array)) 25 | fmt.Println("address2:", address2) 26 | fmt.Println("address1:", address1) 27 | } 28 | -------------------------------------------------------------------------------- /lessons/data_types/unsafe_analysis/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | var ( 10 | x, y int = 1, 2 11 | ) 12 | 13 | p1 := unsafe.Pointer(&x) 14 | p2 := unsafe.Add(p1, 8) 15 | 16 | fmt.Println("p1: ", *(*int)(p1)) 17 | fmt.Println("p2: ", *(*int)(p2)) 18 | 19 | _ = y 20 | } 21 | -------------------------------------------------------------------------------- /lessons/data_types/unsafe_pointer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | var value uint32 = 0xFFFFFFFF 10 | 11 | pointer := unsafe.Pointer(&value) 12 | bytePointer := (*uint8)(pointer) 13 | 14 | fmt.Println("value1:", *bytePointer) 15 | 16 | pointer = unsafe.Add(pointer, 2) 17 | twoBytePointer := (*uint16)(pointer) 18 | 19 | fmt.Println("value2:", *twoBytePointer) 20 | } 21 | -------------------------------------------------------------------------------- /lessons/data_types/unsafe_size_of/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | var value1 int8 = 10 10 | fmt.Println("size1:", unsafe.Sizeof(value1)) // compile time 11 | 12 | var value2 int32 = 10 13 | fmt.Println("size2:", unsafe.Sizeof(value2)) // compile time 14 | } 15 | -------------------------------------------------------------------------------- /lessons/environment/init_in_any_files/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func init() { 6 | fmt.Println("init[main.go] called") 7 | } 8 | 9 | func main() { 10 | fmt.Println("main called") 11 | secondary() 12 | } 13 | -------------------------------------------------------------------------------- /lessons/environment/init_in_any_files/secondary.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func init() { 6 | fmt.Println("init[secondary.go] called") 7 | } 8 | 9 | func secondary() { 10 | fmt.Println("secondary called") 11 | } 12 | -------------------------------------------------------------------------------- /lessons/environment/init_in_any_packages/main/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "golang_course/environment/init_in_any_packages/secondary" 6 | ) 7 | 8 | func init() { 9 | fmt.Println("init[main.go] called") 10 | } 11 | 12 | func main() { 13 | fmt.Println("main called") 14 | secondary.Secondary() 15 | } 16 | -------------------------------------------------------------------------------- /lessons/environment/init_in_any_packages/secondary/secondary.go: -------------------------------------------------------------------------------- 1 | package secondary 2 | 3 | import "fmt" 4 | 5 | func init() { 6 | fmt.Println("init[secondary.go] called") 7 | } 8 | 9 | func Secondary() { 10 | fmt.Println("secondary called") 11 | } 12 | -------------------------------------------------------------------------------- /lessons/environment/init_in_one_file/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func init() { 6 | fmt.Println("first init") 7 | } 8 | 9 | func init() { 10 | fmt.Println("second init") 11 | } 12 | 13 | func main() { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /lessons/environment/init_order/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var value = func() int { 6 | fmt.Println("value initialized") 7 | return 0 8 | }() 9 | 10 | func init() { 11 | fmt.Println("init called") 12 | } 13 | 14 | func main() { 15 | fmt.Println("main called") 16 | } 17 | -------------------------------------------------------------------------------- /lessons/errors/change_global_error/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("io.EOF == io.EOF:", io.EOF == io.EOF) 10 | previousErr := io.EOF 11 | 12 | io.EOF = fmt.Errorf("changed error") 13 | fmt.Println("io.EOF == io.EOF:", io.EOF == io.EOF) 14 | fmt.Println("previousErr == io.EOF:", previousErr == io.EOF) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/errors/constant_error/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | ) 8 | 9 | type Error string 10 | 11 | func (e Error) Error() string { 12 | return string(e) 13 | } 14 | 15 | const ErrEOF = Error("EOF") 16 | 17 | func main() { 18 | var err error = ErrEOF 19 | err = io.EOF 20 | _ = err 21 | 22 | // ErrEOF = Error("new error") -> coplilation error 23 | 24 | anotherErrEOF1 := Error("EOF") 25 | fmt.Println(`anotherErrEOF1 = Error("EOF"):`, anotherErrEOF1 == ErrEOF) 26 | 27 | anotherErrEOF2 := errors.New("EOF") 28 | fmt.Println("anotherErrEOF2 = io.EOF:", anotherErrEOF2 == io.EOF) 29 | } 30 | -------------------------------------------------------------------------------- /lessons/errors/division_by_zero/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func divide(lhs, rhs int) { 6 | defer func() { 7 | fmt.Println("recovered:", recover()) 8 | }() 9 | 10 | _ = lhs / rhs 11 | } 12 | 13 | func main() { 14 | divide(1000, 0) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/errors/division_by_zero_float/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func divide(lhs, rhs float32) float32 { 6 | return lhs / rhs 7 | } 8 | 9 | func main() { 10 | result := divide(1000, 0) 11 | fmt.Println(result) 12 | } 13 | -------------------------------------------------------------------------------- /lessons/errors/errno/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | const ( 6 | OkStatus = iota 7 | EvenNumberErr 8 | ZeroNumberErr 9 | ) 10 | 11 | var Errno = OkStatus 12 | 13 | func divide(lhs, rhs int) int { 14 | if rhs == 0 { 15 | Errno = ZeroNumberErr 16 | return 0 17 | } else if lhs%2 == 0 || rhs%2 == 0 { 18 | Errno = EvenNumberErr 19 | return 0 20 | } 21 | 22 | Errno = OkStatus 23 | return lhs / rhs 24 | } 25 | 26 | func main() { 27 | x := 100 28 | y := 0 29 | 30 | value := divide(x, y) 31 | fmt.Println(value, Errno) 32 | } 33 | -------------------------------------------------------------------------------- /lessons/errors/error_behavior/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type ErrorFromAnotherPackage struct{} 8 | 9 | func (e ErrorFromAnotherPackage) Error() string { 10 | return "error" 11 | } 12 | 13 | func (e ErrorFromAnotherPackage) Path() string { 14 | return "path" 15 | } 16 | 17 | type FSError interface { 18 | Path() string 19 | } 20 | 21 | func IsFSError(err error) bool { 22 | _, ok := err.(FSError) 23 | return ok 24 | } 25 | 26 | func getErrorFromAnotherPackage() error { 27 | return ErrorFromAnotherPackage{} 28 | //return fmt.Errorf("%w", ErrorFromAnotherPackage{}) 29 | } 30 | 31 | func main() { 32 | err := getErrorFromAnotherPackage() 33 | if IsFSError(err) { 34 | fmt.Println("FSError") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lessons/errors/error_flag/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func divideV1(lhs, rhs int) (int, bool) { 6 | if rhs == 0 { 7 | return 0, false 8 | } 9 | 10 | return lhs / rhs, true 11 | } 12 | 13 | func divideV2(lhs, rhs int, status *bool) int { 14 | *status = false 15 | if rhs == 0 { 16 | return 0 17 | } 18 | 19 | *status = true 20 | return lhs / rhs 21 | } 22 | 23 | func main() { 24 | x := 100 25 | y := 0 26 | 27 | value, ok := divideV1(x, y) 28 | fmt.Println(value, ok) 29 | 30 | value = divideV2(x, y, &ok) 31 | fmt.Println(value, ok) 32 | } 33 | -------------------------------------------------------------------------------- /lessons/errors/error_from_defer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "database/sql" 4 | 5 | func getBalance(database *sql.DB, clientId int) (balance float32, err error) { 6 | query := "..." 7 | var rows *sql.Rows 8 | rows, err = database.Query(query, clientId) 9 | if err != nil { 10 | return 0, err 11 | } 12 | 13 | defer func() { 14 | if err == nil { 15 | err = rows.Close() 16 | } 17 | }() 18 | 19 | // reading... 20 | return balance, err 21 | } 22 | -------------------------------------------------------------------------------- /lessons/errors/error_new/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func createErrV1() error { 9 | return errors.New("simple error") 10 | } 11 | 12 | func createErrV2() error { 13 | return fmt.Errorf("error with argument %d", 1000) 14 | } 15 | 16 | func main() { 17 | fmt.Println(createErrV1().Error()) 18 | fmt.Println(createErrV2().Error()) 19 | } 20 | -------------------------------------------------------------------------------- /lessons/errors/error_with_stacktrace/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | func main() { 10 | value, err := DoSomething() 11 | if err != nil { 12 | fmt.Printf("%+v", err) 13 | } 14 | fmt.Println(value) 15 | } 16 | 17 | func DoSomething() (string, error) { 18 | return "", errors.New("some error explanation here") 19 | } 20 | -------------------------------------------------------------------------------- /lessons/errors/errorf/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | err := errors.New("source error") 10 | err = fmt.Errorf("additional error information: %v", err) 11 | 12 | fmt.Println(err.Error()) 13 | fmt.Println(errors.Unwrap(err)) 14 | } 15 | -------------------------------------------------------------------------------- /lessons/errors/errorf_with_packing/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | err := errors.New("source error") 10 | err = fmt.Errorf("additional error information: %w", err) 11 | err = fmt.Errorf("internal error: %w", err) 12 | 13 | fmt.Println(err.Error()) 14 | fmt.Println(errors.Unwrap(err)) 15 | fmt.Println(errors.Unwrap(errors.Unwrap(err))) 16 | fmt.Println(errors.Unwrap(errors.Unwrap(errors.Unwrap(err)))) 17 | } 18 | -------------------------------------------------------------------------------- /lessons/errors/errors_as/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | type DatabaseError struct{} 9 | 10 | func (d DatabaseError) Error() string { 11 | return "database error" 12 | } 13 | 14 | func GetDataFromDB() error { 15 | return fmt.Errorf("failed to get data: %w", DatabaseError{}) 16 | } 17 | 18 | func main() { 19 | err := GetDataFromDB() 20 | if errors.As(err, &DatabaseError{}) { 21 | fmt.Println(err.Error()) 22 | } else { 23 | fmt.Println("unknown error") 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lessons/errors/errors_defer_ignoring/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "database/sql" 4 | 5 | // Need to show solution 6 | 7 | func getBalance(database *sql.DB, clientId int) (float32, error) { 8 | query := "..." 9 | rows, err := database.Query(query, clientId) 10 | if err != nil { 11 | return 0, err 12 | } 13 | 14 | defer rows.Close() 15 | 16 | // reading... 17 | return 0., nil 18 | } 19 | -------------------------------------------------------------------------------- /lessons/errors/errors_handling/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "net/http" 4 | 5 | // Need to show solution 6 | 7 | func authentificate(*http.Request) error 8 | 9 | func Authentificate(request *http.Request) error { 10 | err := authentificate(request) 11 | if err != nil { 12 | return err 13 | } 14 | 15 | return nil 16 | } 17 | -------------------------------------------------------------------------------- /lessons/errors/errors_ignoring/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "errors" 4 | 5 | // Need to show solution 6 | 7 | func process() error { 8 | return errors.New("error") 9 | } 10 | 11 | func main() { 12 | process() 13 | } 14 | -------------------------------------------------------------------------------- /lessons/errors/errors_is/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var ErrDatabaseProblem = errors.New("database problem") 9 | 10 | func GetDataFromDB() error { 11 | return fmt.Errorf("failed to get data: %w", ErrDatabaseProblem) 12 | } 13 | 14 | func main() { 15 | err := GetDataFromDB() 16 | if errors.Is(err, ErrDatabaseProblem) { 17 | fmt.Println(err.Error()) 18 | } else { 19 | fmt.Println("unknown error") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lessons/errors/errors_performance/performance_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | 7 | othererrors "github.com/pkg/errors" 8 | ) 9 | 10 | // go test -bench=. performance_test.go 11 | 12 | var err error 13 | 14 | func BenchmarkErrorWithoutStackTrace(b *testing.B) { 15 | for i := 0; i < b.N; i++ { 16 | err = errors.New("error") 17 | } 18 | } 19 | 20 | func BenchmarkErrorWithStackTrace(b *testing.B) { 21 | for i := 0; i < b.N; i++ { 22 | err = othererrors.New("error") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lessons/errors/errors_type_checking/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type DatabaseError struct{} 8 | 9 | func (d DatabaseError) Error() string { 10 | return "database error" 11 | } 12 | 13 | func GetDataFromDB() error { 14 | return fmt.Errorf("failed to get data: %w", DatabaseError{}) 15 | } 16 | 17 | func main() { 18 | err := GetDataFromDB() 19 | switch err := err.(type) { 20 | case DatabaseError: 21 | fmt.Println(err.Error()) 22 | default: 23 | fmt.Println("unknown error") 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /lessons/errors/errors_value_checking/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var ErrDatabaseProblem = errors.New("database problem") 9 | 10 | func GetDataFromDB() error { 11 | return fmt.Errorf("failed to get data: %w", ErrDatabaseProblem) 12 | } 13 | 14 | func main() { 15 | err := GetDataFromDB() 16 | if err == ErrDatabaseProblem { 17 | fmt.Println(err.Error()) 18 | } else if err != nil { 19 | fmt.Println("unknown error") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lessons/errors/incorrect_wrapping/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | err1 := errors.New("source error 1") 10 | err2 := errors.New("source error 2") 11 | err := fmt.Errorf("additional error information: %w and %w", err1, err2) 12 | 13 | fmt.Println(err.Error()) 14 | fmt.Println(errors.Unwrap(err)) 15 | 16 | err = fmt.Errorf("additional error information: %w", "error") 17 | 18 | fmt.Println(err.Error()) 19 | fmt.Println(errors.Unwrap(err)) 20 | } 21 | -------------------------------------------------------------------------------- /lessons/errors/many_times_handling_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func GetRoute(lat, lon float32) (string, error) { 9 | err := validateCoordinates(lat, lon) 10 | if err != nil { 11 | fmt.Println("incorrect coordinates") // again 12 | return "", err 13 | } 14 | 15 | return "route", nil 16 | } 17 | 18 | func validateCoordinates(lat, lon float32) error { 19 | if lat > 90. || lat < -90. { 20 | fmt.Println("incorrect latitude") 21 | return errors.New("incorrect latitude") 22 | } 23 | if lon > 180. || lon < -180. { 24 | fmt.Println("incorrect longitude") 25 | return errors.New("incorrect longitude") 26 | } 27 | 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /lessons/errors/many_times_handling_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func GetRoute(lat, lon float32) (string, error) { 9 | err := validateCoordinates(lat, lon) 10 | if err != nil { 11 | return "", fmt.Errorf("validation error: %w", err) 12 | } 13 | 14 | return "route", nil 15 | } 16 | 17 | func validateCoordinates(lat, lon float32) error { 18 | if lat > 90. || lat < -90. { 19 | return errors.New("incorrect latitude") 20 | } 21 | if lon > 180. || lon < -180. { 22 | return errors.New("incorrect longitude") 23 | } 24 | 25 | return nil 26 | } 27 | -------------------------------------------------------------------------------- /lessons/errors/nil_pointer_dereference/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func dererence(pointer *int) { 6 | defer func() { 7 | fmt.Println("recovered:", recover()) 8 | }() 9 | 10 | _ = *pointer 11 | } 12 | 13 | func main() { 14 | dererence(nil) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/errors/oom/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // GOGC=off go run main.go 6 | 7 | var data []byte 8 | 9 | func allocate() { 10 | defer func() { 11 | fmt.Println(recover()) 12 | }() 13 | 14 | count := 0 15 | 16 | for { 17 | data = make([]byte, 1<<30) 18 | for idx := 0; idx < 1<<30; idx += 4096 { 19 | data[idx] = 100 20 | } 21 | 22 | fmt.Println("allocated GB:", count) 23 | count++ 24 | } 25 | } 26 | 27 | func main() { 28 | allocate() 29 | } 30 | -------------------------------------------------------------------------------- /lessons/errors/os_exit/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func process() { 9 | defer func() { 10 | recover() 11 | }() 12 | 13 | fmt.Println("V2: open file") 14 | defer fmt.Println("V2: close file") 15 | 16 | os.Exit(1) 17 | } 18 | 19 | func main() { 20 | process() 21 | } 22 | -------------------------------------------------------------------------------- /lessons/errors/panic/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func process() { 8 | fmt.Println("first") 9 | panic("error from process") 10 | fmt.Println("second") 11 | } 12 | 13 | func main() { 14 | defer func() { 15 | if r := recover(); r != nil { 16 | fmt.Println("recover:", r) 17 | } 18 | }() 19 | 20 | process() 21 | } 22 | -------------------------------------------------------------------------------- /lessons/errors/panic_jump/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | value := func() (result int) { 7 | defer func() { 8 | v := recover() 9 | result = v.(int) 10 | }() 11 | 12 | func() { 13 | func() { 14 | func() { 15 | panic(123) 16 | // ... 17 | }() 18 | // ... 19 | }() 20 | // ... 21 | }() 22 | 23 | return 24 | }() 25 | 26 | fmt.Println(value) 27 | } 28 | -------------------------------------------------------------------------------- /lessons/errors/panic_nil/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func panicNil() { 9 | defer func() { 10 | fmt.Println("recovered:", recover()) 11 | }() 12 | 13 | panic(nil) 14 | } 15 | 16 | func panicNilError() { 17 | defer func() { 18 | fmt.Println("recovered:", recover()) 19 | }() 20 | 21 | panic(new(runtime.PanicNilError)) 22 | } 23 | 24 | func main() { 25 | panicNil() 26 | panicNilError() 27 | } 28 | -------------------------------------------------------------------------------- /lessons/errors/panic_rethrow/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func process2() { 8 | defer func() { 9 | e := recover() 10 | fmt.Println("#2 recovered:", e) 11 | panic(e) 12 | }() 13 | 14 | panic("error") 15 | } 16 | 17 | func process1() { 18 | defer func() { 19 | fmt.Println("#1 recovered:", recover()) 20 | }() 21 | 22 | process2() 23 | } 24 | 25 | func main() { 26 | process1() 27 | } 28 | -------------------------------------------------------------------------------- /lessons/errors/panic_task/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | defer func() { 7 | fmt.Println("exited #1") 8 | }() 9 | 10 | fmt.Println("started") 11 | 12 | defer func() { 13 | recover() 14 | fmt.Println("recovered") 15 | }() 16 | 17 | panic("exit") 18 | 19 | fmt.Println("exited #2") 20 | } 21 | -------------------------------------------------------------------------------- /lessons/errors/panic_with_defer_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func processV1() { 6 | defer func() { 7 | recover() 8 | }() 9 | 10 | fmt.Println("V1: open file") 11 | panic("error") 12 | fmt.Println("V1: close file") 13 | } 14 | 15 | func processV2() { 16 | defer func() { 17 | recover() 18 | }() 19 | 20 | fmt.Println("V2: open file") 21 | defer fmt.Println("V2: close file") 22 | 23 | panic("error") 24 | } 25 | 26 | func main() { 27 | processV1() 28 | processV2() 29 | } 30 | -------------------------------------------------------------------------------- /lessons/errors/panic_with_defer_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func process() { 6 | fmt.Println("V2: open file") 7 | defer fmt.Println("V2: close file") 8 | 9 | panic("error") 10 | } 11 | 12 | func main() { 13 | process() 14 | } 15 | -------------------------------------------------------------------------------- /lessons/errors/recover_without_defer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func process2() { 6 | fmt.Println(recover()) 7 | panic("error") 8 | fmt.Println(recover()) 9 | } 10 | 11 | func process1() { 12 | fmt.Println(recover()) 13 | process2() 14 | fmt.Println(recover()) 15 | } 16 | 17 | func main() { 18 | fmt.Println(recover()) 19 | process1() 20 | fmt.Println(recover()) 21 | } 22 | -------------------------------------------------------------------------------- /lessons/errors/replace_panic/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | defer func() { 7 | fmt.Println("recovered:", recover()) 8 | }() 9 | 10 | defer panic(3) // replaced panic(3) 11 | defer panic(2) // replaced panic(3) 12 | defer panic(1) // replaced panic(3) 13 | panic(0) 14 | } 15 | -------------------------------------------------------------------------------- /lessons/errors/runtime_exit/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func process() { 9 | defer func() { 10 | recover() 11 | }() 12 | 13 | fmt.Println("V2: open file") 14 | defer fmt.Println("V2: close file") 15 | 16 | runtime.Goexit() 17 | } 18 | 19 | func main() { 20 | process() 21 | } 22 | -------------------------------------------------------------------------------- /lessons/errors/signal_errors/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "database/sql" 4 | 5 | type Database interface { 6 | Query(string) (string, error) 7 | } 8 | 9 | func RunQueyry(db Database, query string) { 10 | _, err := db.Query(query) 11 | if err == sql.ErrNoRows { 12 | // not found 13 | } else if err != nil { 14 | // error from database 15 | } else { 16 | // ok 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lessons/errors/stack_overflow/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func recursion() { 6 | var data = [10 * 1024 * 1024]int8{} 7 | _ = data 8 | 9 | recursion() 10 | } 11 | 12 | func main() { 13 | defer func() { 14 | if r := recover(); r != nil { 15 | fmt.Println("Recovered in main:", r) 16 | } 17 | }() 18 | 19 | recursion() 20 | } 21 | -------------------------------------------------------------------------------- /lessons/functions/composition/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func sqr(number int) int { 6 | return number * number 7 | } 8 | 9 | func neg(number int) int { 10 | return -number 11 | } 12 | 13 | func compose(fn ...func(int) int) func(int) int { 14 | return func(value int) int { 15 | for _, v := range fn { 16 | value = v(value) 17 | } 18 | 19 | return value 20 | } 21 | } 22 | 23 | func main() { 24 | fn := compose(sqr, neg, sqr) 25 | fmt.Println(fn(4)) 26 | } 27 | -------------------------------------------------------------------------------- /lessons/functions/continuation/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Divide1(lhs, rhs int) int { 6 | if rhs == 0 { 7 | panic("incorrect argument") // Why??? 8 | } else { 9 | return lhs / rhs 10 | } 11 | } 12 | 13 | func Divide2(lhs, rhs int, successFn func(int), errorFn func()) { 14 | if rhs == 0 { 15 | errorFn() 16 | } else { 17 | successFn(lhs / rhs) 18 | } 19 | } 20 | 21 | func main() { 22 | Divide2(100, 10, 23 | func(number int) { 24 | fmt.Println(number) 25 | }, 26 | func() { 27 | fmt.Println("incorrect argument") 28 | }, 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /lessons/functions/currying/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func multiply(x int) func(y int) int { 6 | return func(y int) int { 7 | return x * y 8 | } 9 | } 10 | 11 | func main() { 12 | fmt.Println(multiply(10)(15)) 13 | 14 | // частичное применение 15 | var mult10 = multiply(10) 16 | var mult15 = multiply(15) 17 | 18 | fmt.Println(mult10(5)) 19 | fmt.Println(mult15(15)) 20 | } 21 | -------------------------------------------------------------------------------- /lessons/functions/decorator/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Add(x, y int) int { 6 | return x + y 7 | } 8 | 9 | func Mul(x, y int) int { 10 | return x * y 11 | } 12 | 13 | func Calculate(x, y int, fn func(int, int) int) int { 14 | fmt.Printf("x=%d y=%d\n", x, y) 15 | return fn(x, y) 16 | } 17 | 18 | func CalculateAdd(x, y int) int { 19 | fmt.Printf("x=%d y=%d\n", x, y) 20 | return Add(x, y) 21 | } 22 | 23 | func main() { 24 | Calculate(10, 10, Add) 25 | Calculate(10, 10, Mul) 26 | 27 | CalculateAdd(10, 10) 28 | } 29 | -------------------------------------------------------------------------------- /lessons/functions/defer_calculating/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Need to show solution 6 | 7 | const ( 8 | StatusOk = "ok" 9 | StatusError = "error" 10 | ) 11 | 12 | func notify(status string) { 13 | fmt.Println(status) 14 | } 15 | 16 | func process() { 17 | var status string 18 | defer func(s string) { 19 | notify(s) 20 | }(status) 21 | 22 | // processing.. 23 | status = StatusError 24 | } 25 | 26 | func main() { 27 | process() 28 | } 29 | -------------------------------------------------------------------------------- /lessons/functions/defer_evaluation_moment/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var f func() 7 | defer f() 8 | 9 | f = func() { 10 | fmt.Println(true) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lessons/functions/defer_inactive/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | defer fmt.Println("code") 7 | if false { 8 | defer fmt.Println("unreacheable code") 9 | } 10 | 11 | return 12 | defer fmt.Println("unreacheable code") 13 | } 14 | -------------------------------------------------------------------------------- /lessons/functions/defer_inside_loop/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "os" 4 | 5 | func readFiles(paths []string) error { 6 | for _, path := range paths { 7 | file, err := os.Open(path) 8 | if err != nil { 9 | return err 10 | } 11 | 12 | // reading file... 13 | defer file.Close() 14 | } 15 | 16 | return nil 17 | } 18 | 19 | func main() { 20 | _ = readFiles([]string{"text1.txt", "text2.txt", "text3.txt"}) 21 | } 22 | -------------------------------------------------------------------------------- /lessons/functions/defer_modification_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Modify(value int) (result int) { 6 | defer func() { 7 | result += value 8 | }() 9 | 10 | return value + value 11 | } 12 | 13 | func main() { 14 | fmt.Println(Modify(5)) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/functions/defer_modification_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Modify(value int) int { 6 | var result int 7 | defer func() { 8 | result += value 9 | }() 10 | 11 | return value + value 12 | } 13 | 14 | func main() { 15 | fmt.Println(Modify(5)) 16 | } 17 | -------------------------------------------------------------------------------- /lessons/functions/defer_nil/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | defer fmt.Println("reachable 1") 7 | var f func() 8 | defer f() 9 | 10 | fmt.Println("reachable 2") 11 | } 12 | -------------------------------------------------------------------------------- /lessons/functions/defer_order/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func process1() { 6 | defer fmt.Println(3) 7 | defer fmt.Println(2) 8 | defer fmt.Println(1) 9 | } 10 | 11 | func process2() { 12 | defer func() { 13 | defer fmt.Println(4) 14 | defer fmt.Println(3) 15 | }() 16 | 17 | defer func() { 18 | defer fmt.Println(2) 19 | defer fmt.Println(1) 20 | }() 21 | } 22 | 23 | func main() { 24 | process1() 25 | } 26 | -------------------------------------------------------------------------------- /lessons/functions/defer_performance/comparison_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | // go test -bench=. comparison_test.go 6 | 7 | //go:noinline 8 | func withDefer(a, b int) { 9 | defer func() { 10 | Result = a + b 11 | }() 12 | } 13 | 14 | //go:noinline 15 | func withoutDefer(a, b int) { 16 | Result = a + b 17 | } 18 | 19 | var Result int 20 | 21 | func BenchmarkWithDefer(b *testing.B) { 22 | for i := 0; i < b.N; i++ { 23 | withDefer(-1, i) 24 | } 25 | } 26 | 27 | func BenchmarkWithoutDefer(b *testing.B) { 28 | for i := 0; i < b.N; i++ { 29 | withoutDefer(-1, i) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lessons/functions/defer_union/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func process1() { 6 | defer fmt.Println("test1") 7 | defer fmt.Println("test2") 8 | 9 | // implementation... 10 | } 11 | 12 | func process2() { 13 | defer func() { 14 | fmt.Println("test2") 15 | fmt.Println("test1") 16 | }() 17 | 18 | // implementation... 19 | } 20 | -------------------------------------------------------------------------------- /lessons/functions/defer_with_function/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func get() string { 6 | fmt.Println("1") 7 | return "" 8 | } 9 | 10 | func handle(string) { 11 | fmt.Println("3") 12 | } 13 | 14 | func process() { 15 | defer handle(get()) 16 | fmt.Println("2") 17 | } 18 | 19 | func main() { 20 | process() 21 | } 22 | -------------------------------------------------------------------------------- /lessons/functions/filename_like_argument/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "io" 7 | "os" 8 | ) 9 | 10 | func ProccessDataInFile(filename string) (string, error) { 11 | file, err := os.Open(filename) 12 | if err != nil { 13 | return "", err 14 | } 15 | 16 | var data string 17 | scanner := bufio.NewScanner(file) 18 | for scanner.Scan() { 19 | // processing... 20 | } 21 | 22 | return data, nil 23 | } 24 | 25 | func ProccessData(reader io.Reader) (string, error) { 26 | if reader == nil { 27 | return "", errors.New("incorrect reader") 28 | } 29 | 30 | var data string 31 | scanner := bufio.NewScanner(reader) 32 | for scanner.Scan() { 33 | // processing... 34 | } 35 | 36 | return data, nil 37 | } 38 | -------------------------------------------------------------------------------- /lessons/functions/functions_inlining/comparison_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | // go test -bench=. comparison_test.go 6 | 7 | //go:noinline 8 | func maxWithoutInline(a, b int) int { 9 | if a > b { 10 | return a 11 | } 12 | return b 13 | } 14 | 15 | func maxWithInline(a, b int) int { 16 | if a > b { 17 | return a 18 | } 19 | return b 20 | } 21 | 22 | var Result int 23 | 24 | func BenchmarkMaxWithoutInline(b *testing.B) { 25 | var r int 26 | for i := 0; i < b.N; i++ { 27 | r = maxWithoutInline(-1, i) 28 | } 29 | _ = r 30 | } 31 | 32 | func BenchmarkMaxWithInline(b *testing.B) { 33 | var r int 34 | for i := 0; i < b.N; i++ { 35 | r = maxWithInline(-1, i) 36 | } 37 | _ = r 38 | } 39 | -------------------------------------------------------------------------------- /lessons/functions/generator/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Generator(number int) func() int { 6 | return func() int { 7 | r := number 8 | number++ 9 | return r 10 | } 11 | } 12 | 13 | func main() { 14 | generator := Generator(100) 15 | for i := 0; i <= 200; i++ { 16 | fmt.Println(generator()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lessons/functions/high_order_function/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func forEach(data []int, fn func(int) int) []int { 6 | newData := make([]int, 0, len(data)) 7 | for _, value := range data { 8 | newData = append(newData, fn(value)) 9 | } 10 | 11 | return newData 12 | } 13 | 14 | func main() { 15 | var data = []int{1, 2, 3, 4} 16 | var newData = forEach(data, func(value int) int { 17 | return (value * value) 18 | }) 19 | 20 | fmt.Println(data) 21 | fmt.Println(newData) 22 | } 23 | -------------------------------------------------------------------------------- /lessons/functions/imperative_declarative/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func filterEvenNumbers(numbers []int) []int { 4 | return nil // implemented 5 | } 6 | 7 | func main() { 8 | // imperative way 9 | var imperative []int 10 | for _, number := range []int{1, 2, 3, 4, 5} { 11 | if number%2 != 0 { 12 | imperative = append(imperative, number) 13 | } 14 | } 15 | 16 | // declarative way 17 | declarative := filterEvenNumbers([]int{1, 2, 3, 4, 5}) 18 | _ = declarative 19 | } 20 | -------------------------------------------------------------------------------- /lessons/functions/lazy_evaluation/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type LazyMap func() map[string]string 8 | 9 | func Make(ctr func() map[string]string) LazyMap { 10 | var initialized bool 11 | var data map[string]string 12 | return func() map[string]string { 13 | if !initialized { 14 | data = ctr() 15 | initialized = true 16 | ctr = nil // for GC 17 | } 18 | 19 | return data 20 | } 21 | } 22 | 23 | func main() { 24 | data := Make(func() map[string]string { 25 | return make(map[string]string) 26 | }) 27 | 28 | fmt.Println(data()) 29 | data()["key"] = "value" 30 | fmt.Println(data()) 31 | } 32 | -------------------------------------------------------------------------------- /lessons/functions/memoization/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func Fibonacci(number int) int { 4 | if number <= 2 { 5 | return 1 6 | } 7 | 8 | return Fibonacci(number-1) + Fibonacci(number-2) 9 | } 10 | 11 | func FibonacciWithMemoization(number int) int { 12 | cache := make([]int, number+1) 13 | var impl func(number int) int 14 | impl = func(n int) int { 15 | if cache[n] != 0 { 16 | return cache[n] 17 | } 18 | 19 | if number <= 2 { 20 | return 1 21 | } else { 22 | cache[n] = impl(n-1) + impl(n-2) 23 | } 24 | 25 | return cache[n] 26 | } 27 | 28 | return impl(number) 29 | } 30 | -------------------------------------------------------------------------------- /lessons/functions/named_return_values/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type mobileNavigator struct{} 8 | 9 | func (n mobileNavigator) GetLocation(ctx context.Context, address string) (lat, lon float32, err error) { 10 | if address == "" { 11 | return 12 | } 13 | 14 | if ctx.Err() != nil { 15 | return 16 | } 17 | 18 | // calculating coordinates... 19 | return lat, lon, err 20 | } 21 | -------------------------------------------------------------------------------- /lessons/functions/predicate/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Less(lhs, rhs int) bool { 6 | return lhs < rhs 7 | } 8 | 9 | func Greater(lhs, rhs int) bool { 10 | return lhs > rhs 11 | } 12 | 13 | func Sort(numbers []int, predicate func(int, int) bool) { 14 | for i := 0; i < len(numbers); i++ { 15 | for j := i; j > 0 && predicate(numbers[j-1], numbers[j]); j-- { 16 | numbers[j-1], numbers[j] = numbers[j], numbers[j-1] 17 | } 18 | } 19 | } 20 | 21 | func main() { 22 | numbers := []int{1, 2, 5, 4, 3} 23 | 24 | Sort(numbers, Less) 25 | fmt.Println(numbers) 26 | 27 | Sort(numbers, Greater) 28 | fmt.Println(numbers) 29 | } 30 | -------------------------------------------------------------------------------- /lessons/functions/random_generator/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func produce(source int, permutation func(int) int) func() int { 8 | return func() int { 9 | source = permutation(source) 10 | return source 11 | } 12 | } 13 | 14 | func mutate(number int) int { 15 | return (1664525*number + 1013904223) % 2147483647 16 | } 17 | 18 | func main() { 19 | next := produce(1, mutate) 20 | 21 | fmt.Println(next()) 22 | fmt.Println(next()) 23 | fmt.Println(next()) 24 | fmt.Println(next()) 25 | fmt.Println(next()) 26 | } 27 | -------------------------------------------------------------------------------- /lessons/functions/stack_overflow/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func recursion() { 6 | var data = [10 * 1024 * 1024]int8{} 7 | _ = data 8 | 9 | recursion() 10 | } 11 | 12 | func main() { 13 | defer func() { 14 | if r := recover(); r != nil { 15 | fmt.Println("Recovered in main:", r) 16 | } 17 | }() 18 | 19 | recursion() 20 | } 21 | -------------------------------------------------------------------------------- /lessons/functions/variadic_parameters/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func process(values ...*int) { 6 | fmt.Println(len(values)) 7 | } 8 | 9 | func main() { 10 | process(nil) 11 | process(nil...) 12 | } 13 | -------------------------------------------------------------------------------- /lessons/garbage_collector/big_allocations/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // GOGC=off go run main.go 6 | 7 | var data []byte 8 | 9 | func main() { 10 | count := 0 11 | 12 | for { 13 | data = make([]byte, 1<<30) 14 | for idx := 0; idx < 1<<30; idx += 4096 { 15 | data[idx] = 100 16 | } 17 | 18 | fmt.Println("allocated GB:", count) 19 | count++ 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lessons/garbage_collector/finalizers/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "time" 7 | "unsafe" 8 | ) 9 | 10 | type Data struct { 11 | name string 12 | } 13 | 14 | func NewData(name string) *Data { 15 | data := &Data{ 16 | name: name, 17 | } 18 | 19 | fmt.Println("created", name) 20 | runtime.SetFinalizer(data, func(ptr *Data) { 21 | fmt.Println("finalizer called on addr", unsafe.Pointer(ptr), "value is", ptr.name) 22 | }) 23 | 24 | return data 25 | } 26 | 27 | func main() { 28 | data := NewData("__data__") 29 | _ = data 30 | 31 | runtime.GC() 32 | time.Sleep(time.Second) 33 | } 34 | -------------------------------------------------------------------------------- /lessons/garbage_collector/finalizers_any_times/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func main() { 9 | x := new(int) 10 | *x = 100 11 | 12 | runtime.SetFinalizer(x, func(ptr *int) { 13 | fmt.Println("finalizer called on addr", ptr, "value is", *ptr) 14 | }) 15 | 16 | runtime.SetFinalizer(x, func(ptr *int) { // replace with nil 17 | fmt.Println("finalizer called on addr", ptr, "value is", *ptr) 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /lessons/garbage_collector/finalizers_cycle/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "time" 7 | ) 8 | 9 | type Foo struct { 10 | bar *Bar 11 | } 12 | 13 | type Bar struct { 14 | foo *Foo 15 | } 16 | 17 | func main() { 18 | foo := &Foo{} 19 | bar := &Bar{} 20 | 21 | foo.bar = bar 22 | bar.foo = foo 23 | 24 | runtime.SetFinalizer(foo, func(ptr *Foo) { 25 | fmt.Println("finalizer called on addr", ptr, "value is", *ptr) 26 | }) 27 | 28 | runtime.SetFinalizer(bar, func(ptr *Bar) { 29 | fmt.Println("finalizer called on addr", ptr, "value is", *ptr) 30 | }) 31 | 32 | runtime.GC() 33 | time.Sleep(10 * time.Second) 34 | } 35 | -------------------------------------------------------------------------------- /lessons/garbage_collector/finalizers_not_first_word/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "time" 7 | ) 8 | 9 | type Foo struct { 10 | a int 11 | b string 12 | } 13 | 14 | func main() { 15 | foo := &Foo{a: 1, b: "hello"} 16 | runtime.SetFinalizer(&foo.b, func(ptr *string) { 17 | fmt.Println("finalizer called on addr", ptr, "value is", *ptr) 18 | }) 19 | 20 | runtime.GC() 21 | time.Sleep(time.Second) 22 | } 23 | -------------------------------------------------------------------------------- /lessons/garbage_collector/finalizers_unsafe_type/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func main() { 9 | x := new(int) 10 | *x = 100 11 | 12 | runtime.SetFinalizer(x, func(ptr *float64) { 13 | fmt.Println("finalizer called on addr", ptr, "value is", *ptr) 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/garbage_collector/memory_ballast/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | ballast := make([]byte, 2<<30) 5 | _ = ballast 6 | 7 | // implementation ... 8 | } 9 | -------------------------------------------------------------------------------- /lessons/garbage_collector/weak_ptr/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "time" 7 | "weak" 8 | ) 9 | 10 | func main() { 11 | pointer := new(string) 12 | weakPtr := weak.Make(pointer) 13 | 14 | runtime.GC() 15 | time.Sleep(time.Second) 16 | 17 | fmt.Println(weakPtr.Value() == nil) 18 | } 19 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/cloneable_mixin/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type CloneableMixin[T any] struct{} 9 | 10 | func (m CloneableMixin[T]) Clone() *T { 11 | return new(T) 12 | } 13 | 14 | type Data1 struct { 15 | CloneableMixin[Data1] 16 | } 17 | 18 | type Data2 struct { 19 | CloneableMixin[Data2] 20 | } 21 | 22 | func main() { 23 | data1 := Data1{} 24 | clone1 := data1.Clone() 25 | fmt.Println(reflect.TypeOf(clone1)) // *main.Data1 26 | 27 | data2 := Data2{} 28 | clone2 := data2.Clone() 29 | fmt.Println(reflect.TypeOf(clone2)) // *main.Data2 30 | } 31 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/constraint_with_field_correct/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Data struct { 6 | Value string 7 | } 8 | 9 | func (d Data) GetValue() string { 10 | return d.Value 11 | } 12 | 13 | type ValueGetter interface { 14 | GetValue() string 15 | } 16 | 17 | func Print[T ValueGetter](value T) { 18 | fmt.Println(value.GetValue()) 19 | } 20 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/constraint_with_field_incorrect/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Data1 struct { 6 | Value string 7 | } 8 | 9 | type Data2 struct { 10 | Value string 11 | } 12 | 13 | func Print1[T any](value T) { 14 | fmt.Println(value.Value) // compilation error 15 | } 16 | 17 | func Print2[T Data1 | Data2](value T) { 18 | fmt.Println(value.Value) // compilation error 19 | } 20 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/constraint_with_method/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Stringer interface { 4 | String() string 5 | } 6 | 7 | func ToString[T Stringer](values ...T) []string { 8 | result := make([]string, 0, len(values)) 9 | for idx := range values { 10 | result = append(result, values[idx].String()) 11 | } 12 | 13 | return result 14 | } 15 | 16 | type Data struct{} 17 | 18 | func (d Data) String() string { 19 | return "string" 20 | } 21 | 22 | func main() { 23 | data := Data{} 24 | var idata Stringer = data 25 | 26 | _ = ToString(data) 27 | _ = ToString(idata) 28 | _ = ToString(100) 29 | } 30 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/constraints_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type MyInt int 4 | 5 | func (i MyInt) String() string { 6 | return "number" 7 | } 8 | 9 | type Constraint interface { 10 | ~int | ~int8 | ~int16 | ~int32 | ~int64 11 | String() string 12 | any 13 | 14 | // Do() 15 | // interface{ Do() } 16 | // ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 17 | } 18 | 19 | func Do[T Constraint](value T) { 20 | // ... 21 | } 22 | 23 | func main() { 24 | var value MyInt 25 | Do(value) 26 | } 27 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/constraints_intersection/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // generics restriction 4 | type _ interface { 5 | int | ~int // compilation error 6 | } 7 | 8 | type _ interface { 9 | interface{ int } | interface{ ~int } // ok 10 | } 11 | 12 | type _ interface { 13 | int | interface{ ~int } // ok 14 | } 15 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/constraints_union/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type _ interface { 4 | []int | comparable // compilation error 5 | } 6 | 7 | type _ interface { 8 | string | error // compilation error 9 | } 10 | 11 | type _ interface { 12 | string | interface{ Do() } // compilation error 13 | } 14 | 15 | type _ interface { 16 | string | interface{ int } // ok 17 | } 18 | 19 | type _ interface { 20 | string | interface{} // ok 21 | } 22 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/generic_constraint/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // constraint 4 | type Unsigned interface { 5 | uint | uint8 | uint16 | uint32 | uint64 6 | } 7 | 8 | type Slice[T any] []T 9 | 10 | type SliceConstaint[E Unsigned] interface { 11 | Slice[E] 12 | } 13 | 14 | func Do[E Unsigned, T SliceConstaint[E]](values T) { 15 | // ... 16 | } 17 | 18 | func main() { 19 | var slice1 Slice[uint8] 20 | var slice2 Slice[uint16] 21 | 22 | Do(slice1) 23 | Do(slice2) 24 | } 25 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/generic_decorator/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Decorator[T any](fn func(T), decorator func(T) T) func(T) { 6 | return func(input T) { 7 | fn(decorator(input)) 8 | } 9 | } 10 | 11 | func main() { 12 | print := func(value int) { fmt.Println(value) } 13 | double := func(value int) int { return value * value } 14 | 15 | decorated := Decorator(print, double) 16 | decorated(10) 17 | } 18 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/generic_method_correct/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // constraint 4 | type Signed interface { 5 | int | int8 | int16 | int32 | int64 6 | } 7 | 8 | type Counter struct { 9 | value int64 10 | } 11 | 12 | func Add[T Signed](c *Counter, value T) { 13 | c.value += int64(value) 14 | } 15 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/generic_method_incorrect/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // constraint 4 | type Signed interface { 5 | int | int8 | int16 | int32 | int64 6 | } 7 | 8 | type Counter struct { 9 | value int64 10 | } 11 | 12 | func (c *Counter) Add[T Signed](value T) { // compilation erro 13 | c.value += int64(value) 14 | } -------------------------------------------------------------------------------- /lessons/generics_and_reflection/generic_method_set/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type S struct{} 4 | 5 | func (S) Bar() {} 6 | 7 | type C interface { 8 | S 9 | Foo() 10 | } 11 | 12 | func foobar[T C](value T) { 13 | value.Foo() 14 | value.Bar() // compilation error 15 | } 16 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/generic_set/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Set[K comparable] struct { 6 | data map[K]struct{} 7 | } 8 | 9 | func NewSet[K comparable]() Set[K] { 10 | return Set[K]{ 11 | data: make(map[K]struct{}), 12 | } 13 | } 14 | 15 | func (s *Set[K]) Insert(key K) { 16 | s.data[key] = struct{}{} 17 | } 18 | 19 | func (s *Set[K]) Erase(key K) { 20 | delete(s.data, key) 21 | } 22 | 23 | func (s *Set[K]) Contains(key K) bool { 24 | _, found := s.data[key] 25 | return found 26 | } 27 | 28 | // skipping like with function 29 | func (s *Set[_]) Print() { 30 | fmt.Println(s.data) 31 | } 32 | 33 | func main() { 34 | set := NewSet[string]() 35 | set.Insert("key") 36 | set.Erase("key") 37 | } 38 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/generic_variadic_parameters/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func Process[T any](data ...T) { 4 | // processing 5 | } 6 | 7 | func main() { 8 | Process(2, 5, 10) 9 | Process("one", "two") 10 | Process(0.3) 11 | } 12 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/generics_maps_and_slices/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func process1[T []byte | [2]byte | string](value T) { 4 | _ = value[0] 5 | } 6 | 7 | func process2[T map[int]string](value T) { 8 | _ = value[0] 9 | } 10 | 11 | func process3[T map[int]string|[]byte](value T) { 12 | _ = value[0] 13 | } -------------------------------------------------------------------------------- /lessons/generics_and_reflection/generics_slices_and_strings/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func process[T ~string | ~[]byte](value T, index int) { 4 | _ = value[index] 5 | value[index] = byte('a') // error 6 | } 7 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/generics_with_constants/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func process1[T int]() { 4 | const value T = 5 // compilation error 5 | } 6 | 7 | func process2[T int]() { 8 | var value T = 5 // ok 9 | _ = value 10 | } 11 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/generics_with_pointers/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func process1[T int32 | int64](value *T) { 4 | *value = *value + 1 // ok 5 | } 6 | 7 | func process2[T *int32 | *int64](value T) { 8 | *value = *value + 1 // compilation error 9 | } 10 | 11 | func process3[T *Int, Int int32 | int64](value T) { 12 | *value = *value + 1 // ok 13 | } 14 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/generics_with_unsafe/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "unsafe" 4 | 5 | func store[T any](pointer unsafe.Pointer, value T) { 6 | *(*T)(pointer) = value 7 | } 8 | 9 | func load[T any](pointer unsafe.Pointer) T { 10 | return *(*T)(pointer) 11 | } 12 | 13 | func main() { 14 | var pointer1 unsafe.Pointer // not initialized 15 | var pointer2 unsafe.Pointer // not initialized 16 | 17 | store[int16](pointer1, 100) 18 | store[int32](pointer2, 200) 19 | 20 | value1 := load[int16](pointer1) 21 | value2 := load[int32](pointer2) 22 | 23 | _ = value1 24 | _ = value2 25 | } 26 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/map_keys/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func GetKeys(data map[string]int) []string { 4 | keys := make([]string, 0, len(data)) 5 | for key := range data { 6 | keys = append(keys, key) 7 | } 8 | 9 | return keys 10 | } 11 | 12 | // any -> alias for interface{} 13 | // comparable -> constraint for != and == 14 | func GetKeysGeneric[K comparable, V any](data map[K]V) []K { 15 | keys := make([]K, 0, len(data)) 16 | for key := range data { 17 | keys = append(keys, key) 18 | } 19 | 20 | return keys 21 | } 22 | 23 | func main() { 24 | GetKeys(map[string]int{}) 25 | GetKeysGeneric[int, int](map[int]int{}) 26 | } 27 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/max/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func MaxInt(lhs, rhs int) int { 4 | if lhs >= rhs { 5 | return lhs 6 | } else { 7 | return rhs 8 | } 9 | } 10 | 11 | func MaxUInt(lhs, rhs uint) uint { 12 | if lhs >= rhs { 13 | return lhs 14 | } else { 15 | return rhs 16 | } 17 | } 18 | 19 | func main() { 20 | var lhs1, rhs1 int = 10, 20 21 | _ = MaxInt(lhs1, rhs1) 22 | 23 | var lhs2, rhs2 uint = 10, 20 24 | _ = MaxUInt(lhs2, rhs2) 25 | } 26 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/max_generic/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // constraint 4 | type Signed interface { 5 | int | int8 | int16 | int32 | int64 6 | } 7 | 8 | // constraint 9 | type Unsigned interface { 10 | uint | uint8 | uint16 | uint32 | uint64 11 | } 12 | 13 | // constraint 14 | type Integer interface { 15 | Signed | Unsigned 16 | } 17 | 18 | func Max[T Integer](lhs, rhs T) T { 19 | if lhs >= rhs { 20 | return lhs 21 | } else { 22 | return rhs 23 | } 24 | } 25 | 26 | func main() { 27 | var lhs1, rhs1 int = 10, 20 28 | _ = Max[int](lhs1, rhs1) 29 | 30 | var lhs2, rhs2 uint = 10, 20 31 | _ = Max[uint](lhs2, rhs2) 32 | } 33 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/method_set_constraint/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Data struct{} 4 | 5 | func (d Data) Do1() {} 6 | 7 | type Constraint interface { 8 | Data 9 | Do2() 10 | } 11 | 12 | // generics restriction 13 | func GenericDo[T Constraint](value T) { 14 | value.Do1() // compilation error 15 | value.Do2() // ok 16 | } 17 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/partial_type_alias/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type T[T1 any, T2 any] struct{} 4 | 5 | type TypeAlias1 = T[string, int] 6 | type TypeAlias2[T1 any] = T[T1, int] 7 | 8 | type TypeDefinition1 T[string, int] 9 | type TypeDefinition2[T1 any] T[T1, int] 10 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/private_fields_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "unsafe" 7 | ) 8 | 9 | type Data struct { 10 | value string 11 | } 12 | 13 | func main() { 14 | data := Data{ 15 | value: "it's a secret", 16 | } 17 | 18 | field := reflect.ValueOf(&data).Elem().FieldByName("value") 19 | pointer := unsafe.Pointer(field.UnsafeAddr()) 20 | strPtr := (*string)(pointer) 21 | 22 | *strPtr = "it's not a secret" 23 | fmt.Println(data.value) 24 | } 25 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_can_set/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | var value float64 = 3.14 10 | v := reflect.ValueOf(value) // copy of value 11 | //v.SetFloat(2.7) 12 | //v.Addr() 13 | 14 | fmt.Println("settability of v:", v.CanSet()) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_channel/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | ch := make(chan string, 2) 10 | 11 | vCh := reflect.ValueOf(ch) 12 | vCh.Send(reflect.ValueOf("Go")) 13 | 14 | succeeded := vCh.TrySend(reflect.ValueOf("C++")) 15 | fmt.Println("C++", succeeded) 16 | 17 | succeeded = vCh.TrySend(reflect.ValueOf("Java")) 18 | fmt.Println("Java", succeeded) 19 | 20 | fmt.Println(vCh.Len(), vCh.Cap()) 21 | 22 | value, ok := vCh.Recv() 23 | fmt.Println(value, ok) 24 | 25 | value, ok = vCh.TryRecv() 26 | fmt.Println(value, ok) 27 | 28 | value, ok = vCh.TryRecv() 29 | fmt.Println(value, ok) 30 | 31 | vCh.Close() 32 | } 33 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_comparable/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | var str string 10 | var number int 11 | var slice []int 12 | 13 | fmt.Println("str:", reflect.ValueOf(str).Comparable()) 14 | fmt.Println("number:", reflect.ValueOf(number).Comparable()) 15 | fmt.Println("slice:", reflect.ValueOf(slice).Comparable()) 16 | } 17 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_convertible/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | vData := reflect.ValueOf([]int{1, 2, 3}) 10 | 11 | tData := vData.Type() 12 | t1 := reflect.TypeOf(&[3]int{}) 13 | t2 := reflect.TypeOf([3]int{}) 14 | 15 | fmt.Println(tData.ConvertibleTo(t1)) 16 | fmt.Println(tData.ConvertibleTo(t2)) 17 | 18 | fmt.Println(vData.CanConvert(t1)) 19 | fmt.Println(vData.CanConvert(t2)) 20 | } 21 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_creation/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | dataStruct := reflect.StructOf([]reflect.StructField{ 10 | {Name: "Age", Type: reflect.TypeOf("abc")}, 11 | }) 12 | 13 | fmt.Println("dataStruct:", dataStruct) 14 | 15 | dataArray := reflect.ArrayOf(5, reflect.TypeOf(123)) 16 | 17 | fmt.Println("dataArray:", dataArray) 18 | 19 | dataPointer := reflect.PointerTo(dataArray) 20 | 21 | fmt.Println("dataPointer:", dataPointer) 22 | } 23 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_dynamic_type/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | var z = 100 10 | var y = &z 11 | var x interface{} = y 12 | 13 | v := reflect.ValueOf(&x) 14 | vx := v.Elem() 15 | vy := vx.Elem() 16 | vz := vy.Elem() 17 | 18 | fmt.Println(vx, vy, vz) 19 | vz.Set(reflect.ValueOf(200)) 20 | fmt.Println(vx, vy, vz) 21 | } 22 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_implements/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type Interface interface { 9 | Method() 10 | } 11 | 12 | type Data struct{} 13 | 14 | func (c Data) Method() {} 15 | 16 | func main() { 17 | dataType := reflect.TypeOf(Data{}) 18 | interfaceType := reflect.TypeOf((*Interface)(nil)).Elem() 19 | fmt.Println("implements:", dataType.Implements(interfaceType)) 20 | } 21 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_interface_method/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | var value float32 = 3.14 10 | v := reflect.ValueOf(value) 11 | iValue := v.Interface() 12 | fmt.Println(iValue.(float32)) 13 | } 14 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_leak/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func main() { 8 | pointer1 := reflect.ValueOf(new(int)).Pointer() // unsafe 9 | pointer2 := reflect.ValueOf(new(int)).UnsafePointer() // safe 10 | 11 | _ = pointer1 12 | _ = pointer2 13 | } 14 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_map/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | data := map[string]int{"data1": 100, "data2": 200} 10 | 11 | vData := reflect.ValueOf(data) 12 | vData.SetMapIndex(reflect.ValueOf("data1"), reflect.ValueOf(1000)) 13 | vData.SetMapIndex(reflect.ValueOf("data2"), reflect.ValueOf(2000)) 14 | 15 | for it := vData.MapRange(); it.Next(); { 16 | fmt.Println(it.Key(), it.Value()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_nothing/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | var value1 reflect.Value 10 | fmt.Println(value1) 11 | 12 | value2 := reflect.ValueOf((*int)(nil)).Elem() 13 | fmt.Println(value2) 14 | 15 | value3 := reflect.ValueOf([]interface{}{nil}).Index(0) 16 | fmt.Println(value3) 17 | } 18 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_select/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | ch := make(chan int, 1) 10 | 11 | vch := reflect.ValueOf(ch) 12 | succeed := vch.TrySend(reflect.ValueOf(100)) 13 | fmt.Println(succeed, vch.Len(), vch.Cap()) 14 | 15 | branches := []reflect.SelectCase{ 16 | {Dir: reflect.SelectDefault}, 17 | {Dir: reflect.SelectRecv, Chan: vch}, 18 | } 19 | 20 | index, vRecv, recvOk := reflect.Select(branches) 21 | fmt.Println(index, vRecv, recvOk) 22 | 23 | vch.Close() 24 | } 25 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_struct_field_tags/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type Data struct { 9 | X int `json:"x" xml:"name"` 10 | Y bool `json:"y,omitempty"` 11 | } 12 | 13 | func main() { 14 | t := reflect.TypeOf(Data{}) 15 | tXTag := t.Field(0).Tag 16 | tYTag := t.Field(1).Tag 17 | 18 | fmt.Println(reflect.TypeOf(tXTag), reflect.TypeOf(tYTag)) 19 | 20 | value, present := tXTag.Lookup("json") 21 | fmt.Println(value, present) 22 | value, present = tYTag.Lookup("json") 23 | fmt.Println(value, present) 24 | } 25 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_typeof_and_valueof/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | var value float64 = 3.4 10 | 11 | // неявное преобразование в пустой интерфейс 12 | fmt.Println("type:", reflect.TypeOf(value)) // func TypeOf(i any) reflect.Type 13 | fmt.Println("type:", reflect.ValueOf(value)) // func ValueOf(i any) reflect.Value 14 | 15 | equal := reflect.ValueOf(value).Type() == reflect.TypeOf(value) 16 | fmt.Println("equal:", equal) 17 | 18 | kind := reflect.ValueOf(value).Kind() 19 | fmt.Println("equal reflect.Float64:", reflect.Float64 == kind) 20 | 21 | value = reflect.ValueOf(value).Float() 22 | _ = value 23 | } 24 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_with_big_type/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | var x uint8 = 10 10 | v := reflect.ValueOf(x) 11 | 12 | fmt.Println("type:", v.Type()) 13 | fmt.Println("kind:", v.Kind()) 14 | 15 | x = uint8(v.Uint()) // uint64 16 | _ = x 17 | } 18 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_with_struct_fields/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type Data struct { 9 | Value1 int 10 | value2 int 11 | } 12 | 13 | func main() { 14 | data := Data{Value1: 100, value2: 200} 15 | v := reflect.ValueOf(&data).Elem() 16 | t := v.Type() 17 | 18 | for idx := 0; idx < v.NumField(); idx++ { 19 | field := v.Field(idx) 20 | fmt.Println(t.Field(idx).Name, field.CanSet(), field.CanAddr()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/reflect_with_type_definition/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type IntAlias = int 9 | type IntDefinition int 10 | 11 | func main() { 12 | var value1 IntAlias = 7 13 | v1 := reflect.ValueOf(value1) 14 | 15 | fmt.Println("alias type:", v1.Type()) 16 | fmt.Println("alias kind:", v1.Kind()) 17 | 18 | var value2 IntDefinition = 7 19 | v2 := reflect.ValueOf(value2) 20 | 21 | fmt.Println("definition type:", v2.Type()) 22 | fmt.Println("definition kind:", v2.Kind()) 23 | } 24 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/type_aliases/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type NewType[T any] T // may not be used as the source types 4 | 5 | type Set1[K comparable] map[K]struct{} 6 | type Set2[K comparable] = map[K]struct{} // generic type aliases are not supported 7 | 8 | type SetBool1 Set1[bool] 9 | type SetBool2 = Set1[bool] 10 | 11 | type Comparable1 comparable 12 | type Comparable2 = comparable 13 | 14 | type Constraint1 interface{ int | uint } 15 | type Constraint2 = interface{ int | uint } 16 | 17 | func main() { 18 | setStr := Set1[string]{} 19 | _ = setStr 20 | 21 | setBool := SetBool1{} 22 | _ = setBool 23 | } 24 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/type_inference/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Create[T any]() *T { 6 | return new(T) 7 | } 8 | 9 | func Print[T any](value T) { 10 | fmt.Println() 11 | } 12 | 13 | func MultiplePrint[T1 any, T2 any](lhs T1, rhs T2) { 14 | fmt.Println(lhs, rhs) 15 | } 16 | 17 | type Data[T any] struct { 18 | Value T 19 | } 20 | 21 | func main() { 22 | // without infence 23 | value1 := Create() 24 | _ = value1 25 | var value2 *int = Create() 26 | _ = value2 27 | 28 | // with infence 29 | Print(100) 30 | Print("hello") 31 | MultiplePrint(100, "hello") 32 | 33 | // without infence 34 | data1 := Data{} 35 | _ = data1 36 | data2 := Data{Value: 100} 37 | _ = data2 38 | } 39 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/type_parameter_embedding/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Base1[Derived any] struct { 4 | Derived // compilation error 5 | } 6 | 7 | type Base2[Derived any] struct { 8 | d Derived // ok 9 | } 10 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/universal_fabric/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Creator[T any] func() T 4 | 5 | func NewInstance[T any](creator Creator[T]) T { 6 | return creator() 7 | } 8 | 9 | type ( 10 | Book struct{} 11 | Game struct{} 12 | ) 13 | 14 | func main() { 15 | bookCreator := func() Book { return Book{} } 16 | gameCreator := func() Game { return Game{} } 17 | 18 | book := NewInstance(bookCreator) 19 | _ = book 20 | 21 | game := NewInstance(gameCreator) 22 | _ = game 23 | } 24 | -------------------------------------------------------------------------------- /lessons/generics_and_reflection/unnamed_types/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func process1[T1 int, T2 *T1]() { 4 | } 5 | 6 | func process2[T1 *T2, T2 int]() { 7 | } 8 | 9 | func process3[T1 *T1]() { 10 | } 11 | 12 | func process4[T ~string | ~int, A ~[2]T, B ~chan T]() { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /lessons/goroutines_and_scheduler/async_preemptible/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "runtime" 6 | ) 7 | 8 | func infiniteLoop(str string) { 9 | for { 10 | log.Println(str) 11 | } 12 | } 13 | 14 | func loop(str string) { 15 | for i := 0; i < 5; i++ { 16 | runtime.Gosched() 17 | log.Println(str) 18 | } 19 | } 20 | 21 | func main() { 22 | runtime.GOMAXPROCS(1) 23 | go infiniteLoop("infinite_loop") 24 | loop("loop") 25 | } 26 | -------------------------------------------------------------------------------- /lessons/goroutines_and_scheduler/endless_loop/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func main() { 9 | runtime.GOMAXPROCS(1) 10 | 11 | var i int 12 | go func() { 13 | for { 14 | i++ 15 | } 16 | }() 17 | 18 | fmt.Println(i) 19 | } 20 | -------------------------------------------------------------------------------- /lessons/goroutines_and_scheduler/gmp_model/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0)) 10 | fmt.Println("CPU:", runtime.NumCPU()) 11 | 12 | runtime.GOMAXPROCS(16) 13 | 14 | fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0)) 15 | fmt.Println("CPU:", runtime.NumCPU()) 16 | } 17 | -------------------------------------------------------------------------------- /lessons/goroutines_and_scheduler/goroutine_index/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | for i := 0; i < 5; i++ { 10 | go func() { 11 | fmt.Print(i) 12 | }() 13 | } 14 | 15 | time.Sleep(2 * time.Second) 16 | } 17 | -------------------------------------------------------------------------------- /lessons/goroutines_and_scheduler/goroutines_number/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func main() { 9 | fmt.Printf("Goroutines: %d\n", runtime.NumGoroutine()) 10 | } 11 | -------------------------------------------------------------------------------- /lessons/goroutines_and_scheduler/never_exit/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "time" 6 | ) 7 | 8 | func task() { 9 | for { 10 | time.Sleep(time.Millisecond * 200) 11 | panic("unexpected situation") 12 | } 13 | } 14 | 15 | func NeverExit(name string, action func()) { 16 | defer func() { 17 | if v := recover(); v != nil { 18 | log.Println(name, "is crashed - restarting...") 19 | go NeverExit(name, action) 20 | } 21 | }() 22 | 23 | if action != nil { 24 | action() 25 | } 26 | } 27 | 28 | func main() { 29 | go NeverExit("first_goroutine", task) 30 | go NeverExit("second_goroutine", task) 31 | 32 | time.Sleep(time.Second) 33 | } 34 | -------------------------------------------------------------------------------- /lessons/goroutines_and_scheduler/panic_from_other_goroutine/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func process() { 9 | defer func() { 10 | v := recover() 11 | fmt.Println("recovered:", v) 12 | }() 13 | 14 | go func() { 15 | panic("error") 16 | }() 17 | 18 | time.Sleep(time.Second) 19 | } 20 | 21 | func main() { 22 | process() 23 | } 24 | -------------------------------------------------------------------------------- /lessons/goroutines_and_scheduler/runtime_exit/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | go func() { 11 | for { 12 | time.Sleep(time.Second) 13 | fmt.Println("tick") 14 | } 15 | }() 16 | 17 | time.Sleep(3 * time.Second) 18 | runtime.Goexit() 19 | } 20 | -------------------------------------------------------------------------------- /lessons/goroutines_and_scheduler/tcp_server_with_panic/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "log" 6 | "net" 7 | ) 8 | 9 | // nc 127.0.0.1 12345 10 | 11 | func main() { 12 | listener, err := net.Listen("tcp", ":12345") 13 | if err != nil { 14 | log.Fatal(err) 15 | } 16 | 17 | for { 18 | conn, err := listener.Accept() 19 | if err != nil { 20 | log.Println(err) 21 | } 22 | 23 | go ClientHandler(conn) 24 | } 25 | } 26 | 27 | func ClientHandler(c net.Conn) { 28 | panic(errors.New("internal error")) 29 | } 30 | -------------------------------------------------------------------------------- /lessons/goroutines_and_scheduler/tcp_server_without_panic/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | ) 7 | 8 | // nc 127.0.0.1 12345 9 | 10 | func main() { 11 | listener, err := net.Listen("tcp", ":12345") 12 | if err != nil { 13 | log.Fatal(err) 14 | } 15 | 16 | for { 17 | conn, err := listener.Accept() 18 | if err != nil { 19 | log.Println(err) 20 | } 21 | 22 | go ClientHandler(conn) 23 | } 24 | } 25 | 26 | func ClientHandler(c net.Conn) { 27 | defer func() { 28 | if v := recover(); v != nil { 29 | log.Println("captured panic:", v) 30 | } 31 | c.Close() 32 | }() 33 | 34 | panic("internal error") 35 | } 36 | -------------------------------------------------------------------------------- /lessons/interfaces/call_interface_method/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Interface interface { 6 | process(int) bool 7 | } 8 | 9 | type String string 10 | 11 | func (s String) process(size int) bool { 12 | return len(s) > size 13 | } 14 | 15 | func main() { 16 | var i String = String("inteface") 17 | fmt.Println(i.process(10)) 18 | fmt.Println(Interface.process(i, 10)) 19 | fmt.Println(interface{ process(int) bool }.process(i, 10)) 20 | } 21 | -------------------------------------------------------------------------------- /lessons/interfaces/compare_interfaces/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var lhs interface{} = []int{1, 2, 3} 7 | var rhs interface{} = []int{1, 2, 3} 8 | fmt.Println(lhs == rhs) 9 | } 10 | -------------------------------------------------------------------------------- /lessons/interfaces/consumer_interface/entity/client.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | type Client struct { 4 | Id int 5 | Name string 6 | Surname string 7 | Age int 8 | Address string 9 | } 10 | -------------------------------------------------------------------------------- /lessons/interfaces/consumer_interface/service/client_updater.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import "golang_course/lessons/interfaces/consumer_interface/entity" 4 | 5 | type clientUpdater interface { 6 | UpdateClient(entity.Client) error 7 | } 8 | 9 | type ClientUpdater struct { 10 | repository clientUpdater 11 | } 12 | 13 | func NewClientUpdater(repository clientUpdater) ClientUpdater { 14 | return ClientUpdater{ 15 | repository: repository, 16 | } 17 | } 18 | 19 | func (s *ClientUpdater) UpdateClient(client entity.Client) error { 20 | return s.repository.UpdateClient(client) 21 | } 22 | -------------------------------------------------------------------------------- /lessons/interfaces/consumer_interface/service/message_sender.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import "golang_course/lessons/interfaces/consumer_interface/entity" 4 | 5 | type clientGetter interface { 6 | GetClient(int) (entity.Client, error) 7 | } 8 | 9 | type MessageSender struct { 10 | repository clientGetter 11 | } 12 | 13 | func NewMessageSender(repository clientGetter) MessageSender { 14 | return MessageSender{ 15 | repository: repository, 16 | } 17 | } 18 | 19 | func (s *MessageSender) SendMessage(userId int, message string) error { 20 | _, err := s.repository.GetClient(userId) 21 | if err != nil { 22 | return err 23 | } 24 | 25 | // send message to client 26 | 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /lessons/interfaces/different_interfaces/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Stringer interface { 4 | String() string 5 | } 6 | 7 | // Embeds all types whose underlying type is []byte 8 | type AnyByteSlice interface { 9 | ~[]byte 10 | } 11 | 12 | // Embeds type union 13 | type Unsigned interface { 14 | uint | uintptr | uint8 | uint16 | uint32 | uint64 15 | } 16 | 17 | func main() { 18 | var stringer Stringer 19 | _ = stringer 20 | 21 | var any AnyByteSlice 22 | _ = any 23 | 24 | var unsigned Unsigned 25 | _ = unsigned 26 | } 27 | -------------------------------------------------------------------------------- /lessons/interfaces/duck_typing/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Need to show solution 6 | 7 | type Duck interface { 8 | Talk() string 9 | Walk() 10 | Swim() 11 | } 12 | 13 | type Dog struct{} 14 | 15 | func (d Dog) Talk() string { 16 | return "AAAGGGRRR" 17 | } 18 | 19 | func (d Dog) Walk() { 20 | fmt.Println("Walking...") 21 | } 22 | 23 | func (d Dog) Swim() { 24 | fmt.Println("Swimming...") 25 | } 26 | 27 | func CatchDuck(duck Duck) { 28 | fmt.Println("Catching...") 29 | } 30 | 31 | func main() { 32 | dog := Dog{} 33 | CatchDuck(dog) 34 | } 35 | -------------------------------------------------------------------------------- /lessons/interfaces/duck_typing_problem/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "context" 4 | 5 | type UserService interface { 6 | Save(ctx context.Context, name string) (int64, error) 7 | Get(ctx context.Context, id int64) (interface{}, error) 8 | } 9 | 10 | type UserRepository interface { 11 | Save(ctx context.Context, name string) (int64, error) 12 | Get(ctx context.Context, id int64) (interface{}, error) 13 | } 14 | 15 | type Provider struct{} 16 | 17 | func NewProvider() Provider { 18 | return Provider{} 19 | } 20 | 21 | func (p *Provider) ProvideUserRepo() UserService 22 | -------------------------------------------------------------------------------- /lessons/interfaces/empty_interface/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Nothing interface{} 4 | 5 | func main() { 6 | var nothing Nothing 7 | var empty interface{} 8 | var any any 9 | 10 | nothing = empty 11 | nothing = any 12 | 13 | empty = nothing 14 | empty = any 15 | 16 | any = nothing 17 | any = empty 18 | } 19 | -------------------------------------------------------------------------------- /lessons/interfaces/empty_interfaces_conversion/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Aboutable interface { 6 | About() string 7 | } 8 | 9 | type Book struct { 10 | name string 11 | } 12 | 13 | func (book *Book) About() string { 14 | return "Book: " + book.name 15 | } 16 | 17 | func main() { 18 | var a Aboutable = &Book{"Go 101"} 19 | fmt.Println(a) // &{Go 101} 20 | 21 | var i interface{} = &Book{"Rust 101"} 22 | fmt.Println(i) // &{Rust 101} 23 | 24 | i = 100 25 | fmt.Println(i) // 100 26 | } 27 | -------------------------------------------------------------------------------- /lessons/interfaces/empty_interfaces_use_case/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Cient struct{} 4 | type Admin struct{} 5 | 6 | type Storage struct{} 7 | 8 | func (s *Storage) Get(id int) (interface{}, error) { 9 | // already implemented 10 | return nil, nil 11 | } 12 | 13 | func (s *Storage) Set(id int, user interface{}) error { 14 | // already implemented 15 | return nil 16 | } 17 | -------------------------------------------------------------------------------- /lessons/interfaces/generic_tree/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type BSTItem interface { 4 | Less(BSTItem) bool 5 | } 6 | 7 | type BSTNode struct { 8 | item BSTItem 9 | left *BSTNode 10 | right *BSTNode 11 | } 12 | -------------------------------------------------------------------------------- /lessons/interfaces/incorrect_methods/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Shape interface { 4 | Area() float64 5 | } 6 | 7 | type Circle struct { 8 | radius float64 9 | } 10 | 11 | func (c Circle) Area() int { 12 | return int(3.14 * c.radius * c.radius) 13 | } 14 | 15 | func main() { 16 | circle := Circle{} 17 | var iface interface{} = circle 18 | shape := iface.(Shape) 19 | _ = shape 20 | } 21 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_allocation/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // go build -gcflags '-l -m' 6 | 7 | func printValue(v interface{}) { 8 | fmt.Println(v) 9 | /* 10 | println(v) 11 | _, _ = v.(int) 12 | */ 13 | } 14 | 15 | func main() { 16 | var num1 int = 10 17 | var str1 string = "Hello" 18 | 19 | printValue(num1) 20 | printValue(str1) 21 | 22 | var num2 int = 10 23 | var str2 string = "Hello" 24 | 25 | var i interface{} 26 | i = num2 27 | i = str2 28 | _ = i 29 | } 30 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_assignment/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type A interface { 4 | Do() 5 | } 6 | 7 | type B interface { 8 | Do() 9 | } 10 | 11 | func main() { 12 | var a A 13 | var b B 14 | 15 | // Does not work with 16 | // different packages 17 | 18 | a = b 19 | b = a 20 | } 21 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_composition/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Greater interface { 6 | Hello() 7 | } 8 | 9 | type Stranger interface { 10 | Greater 11 | Hello() 12 | } 13 | 14 | func main() { 15 | var s Stranger 16 | fmt.Println(s) 17 | } 18 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_composition_with_struct/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Data struct{} 4 | 5 | func (d Data) Print() 6 | 7 | type StrData interface { 8 | Data 9 | String() 10 | } 11 | 12 | func main() { 13 | var data StrData 14 | _ = data 15 | } 16 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_copy/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | type eface struct { 9 | typ unsafe.Pointer 10 | val unsafe.Pointer 11 | } 12 | 13 | func main() { 14 | var value int = 100 15 | var i interface{} = value 16 | fmt.Println(i) 17 | 18 | value = 200 19 | fmt.Println(i) 20 | 21 | obj := (*eface)(unsafe.Pointer(&i)) 22 | println("&value:", &value) 23 | println("obj.val:", obj.val) 24 | 25 | } 26 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_guard/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "io" 4 | 5 | type T struct { 6 | //... 7 | } 8 | 9 | // Interface guard 10 | var _ io.ReadWriter = (*T)(nil) 11 | 12 | func (t *T) Read(p []byte) (n int, err error) { 13 | return 0, nil 14 | } 15 | 16 | func (t *T) Write(p []byte) (n int, err error) { 17 | return 0, nil 18 | } 19 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_internals/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | type eface struct { 9 | typ unsafe.Pointer 10 | val unsafe.Pointer 11 | } 12 | 13 | func main() { 14 | var value int = 100 15 | var i interface{} = value 16 | fmt.Println("before:", i) 17 | 18 | obj := (*eface)(unsafe.Pointer(&i)) 19 | *(*int)(obj.val) = 200 20 | fmt.Println("after:", i) 21 | } 22 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_key_in_map/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var data []int 5 | dictionary := make(map[interface{}]struct{}) 6 | dictionary[data] = struct{}{} 7 | } 8 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_not_nil_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type MyError struct{} 6 | 7 | func (e *MyError) Error() string { 8 | return "error" 9 | } 10 | 11 | func main() { 12 | var pointer *MyError = nil 13 | var err error = pointer 14 | fmt.Println("nil:", err == nil) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_not_nil_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func ReadFile(filename string) (err error) { 9 | var internalErr *os.PathError 10 | 11 | if filename == "" { 12 | return internalErr 13 | } 14 | 15 | // reading... 16 | return nil 17 | } 18 | 19 | func main() { 20 | err := ReadFile("") 21 | if err != nil { 22 | fmt.Println("error") 23 | } else { 24 | fmt.Println("nil") 25 | } 26 | 27 | fmt.Println("value of err: ", err) 28 | fmt.Printf("type of err: %T\n", err) 29 | fmt.Println("(err == nil): ", err == nil) 30 | 31 | } 32 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_not_nil_3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Data struct { 6 | value int 7 | } 8 | 9 | func Process(i interface{}) { 10 | fmt.Println("nil:", i == nil) 11 | } 12 | 13 | func main() { 14 | var data *Data = nil 15 | Process(data) 16 | } 17 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_with_receiver/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Interface interface { 4 | Do() 5 | } 6 | 7 | type Object1 struct{} 8 | 9 | func (o *Object1) Do() {} 10 | 11 | type Object2 struct{} 12 | 13 | func (o Object2) Do() {} 14 | 15 | func main() { 16 | var i Interface 17 | 18 | i = &Object1{} 19 | 20 | i = Object2{} 21 | i = &Object2{} 22 | 23 | _ = i 24 | } 25 | -------------------------------------------------------------------------------- /lessons/interfaces/interface_with_receiver_reason/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Getter interface { 4 | Get() interface{} 5 | } 6 | 7 | type PointerGetter struct{} 8 | 9 | func (p *PointerGetter) Get() interface{} { 10 | return nil 11 | } 12 | 13 | func get() PointerGetter { 14 | return PointerGetter{} 15 | } 16 | 17 | func main() { 18 | var ptrGetter PointerGetter 19 | ptrGetter.Get() // ok 20 | 21 | var getter Getter = get() // error 22 | _ = getter 23 | } 24 | -------------------------------------------------------------------------------- /lessons/interfaces/numbers_comparison/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | var x interface{} = 3 9 | var y interface{} = 3 10 | fmt.Println(x == y) 11 | } 12 | -------------------------------------------------------------------------------- /lessons/interfaces/polymorphism/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Figure interface { 6 | Area() int 7 | } 8 | 9 | type Square struct { 10 | x int 11 | } 12 | 13 | func (s Square) Area() int { 14 | return s.x * s.x 15 | } 16 | 17 | type Rectangle struct { 18 | x int 19 | y int 20 | } 21 | 22 | func (r Rectangle) Area() int { 23 | return r.x * r.y 24 | } 25 | 26 | func main() { 27 | figures := []Figure{Square{10}, Rectangle{10, 20}} 28 | for _, figure := range figures { 29 | fmt.Println(figure.Area()) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lessons/interfaces/producer_interface/service/client_updater.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import "golang_course/lessons/interfaces/producer_interface/storage" 4 | 5 | type ClientUpdater struct { 6 | repository storage.ClientStorage 7 | } 8 | 9 | func NewClientUpdater(repository storage.ClientStorage) ClientUpdater { 10 | return ClientUpdater{ 11 | repository: repository, 12 | } 13 | } 14 | 15 | func (s *ClientUpdater) UpdateClient(client storage.Client) error { 16 | return s.repository.UpdateClient(client) 17 | } 18 | -------------------------------------------------------------------------------- /lessons/interfaces/producer_interface/service/message_sender.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import "golang_course/lessons/interfaces/producer_interface/storage" 4 | 5 | type MessageSender struct { 6 | repository storage.ClientStorage 7 | } 8 | 9 | func NewMessageSender(repository storage.ClientStorage) MessageSender { 10 | return MessageSender{ 11 | repository: repository, 12 | } 13 | } 14 | 15 | func (s *MessageSender) SendMessage(userId int, message string) error { 16 | _, err := s.repository.GetClient(userId) 17 | if err != nil { 18 | return err 19 | } 20 | 21 | // send message to client 22 | 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /lessons/interfaces/producer_interface/storage/client.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | type Client struct { 4 | Id int 5 | Name string 6 | Surname string 7 | Age int 8 | Address string 9 | } 10 | 11 | type ClientStorage interface { 12 | GetAllClients() ([]Client, error) 13 | GetClientsByAge(int) ([]Client, error) 14 | GetClient(int) (Client, error) 15 | RemoveClient(int) error 16 | UpdateClient(Client) error 17 | CreateClient(Client) error 18 | // ... 19 | } 20 | -------------------------------------------------------------------------------- /lessons/interfaces/slice_values_to_slice_interfaces/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var interfaces []interface{} 7 | values := []int{100, 200, 300, 400, 500} 8 | 9 | // interfaces = values -> compilation error 10 | 11 | interfaces = make([]interface{}, len(values)) 12 | for idx := 0; idx < len(values); idx++ { 13 | interfaces[idx] = values[idx] 14 | } 15 | 16 | fmt.Println(interfaces...) 17 | } 18 | -------------------------------------------------------------------------------- /lessons/interfaces/static_and_dynamic_type/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type Stringer interface { 8 | String() string 9 | } 10 | 11 | func main() { 12 | var s Stringer // static type 13 | s = time.Time{} // dynamic type 14 | _ = s 15 | } 16 | -------------------------------------------------------------------------------- /lessons/interfaces/type_assertion_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var value int = 100 7 | var i interface{} = value 8 | 9 | converted1, ok1 := i.(int) 10 | if ok1 { 11 | fmt.Println("converted1 int:", converted1) 12 | } 13 | 14 | converted2, ok2 := i.(float32) 15 | if ok2 { 16 | fmt.Println("converted2 float32:", converted2) 17 | } 18 | 19 | converted3 := i.(int) 20 | fmt.Println("converted3 int:", converted3) 21 | converted4 := i.(float32) 22 | fmt.Println("converted4 float32:", converted4) 23 | } 24 | -------------------------------------------------------------------------------- /lessons/interfaces/type_assertion_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type fooer interface{ foo() } 6 | type barer interface{ bar() } 7 | type foobarer interface { 8 | foo() 9 | bar() 10 | } 11 | 12 | type thing struct{} 13 | 14 | func (t *thing) foo() {} 15 | func (t *thing) bar() {} 16 | 17 | func main() { 18 | var i foobarer = &thing{} 19 | _, ok := i.(fooer) 20 | fmt.Println("result:", ok) 21 | } 22 | -------------------------------------------------------------------------------- /lessons/interfaces/type_assertion_3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type fooer interface{ foo() } 6 | 7 | type thing struct{} 8 | 9 | func (t *thing) foo() {} 10 | func (t *thing) bar() {} 11 | 12 | func main() { 13 | var i fooer = &thing{} 14 | 15 | // dynamically checking for certain methods 16 | _, ok := i.(interface{ bar() }) 17 | fmt.Println("result:", ok) 18 | } 19 | -------------------------------------------------------------------------------- /lessons/interfaces/type_switch_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func do(i interface{}) { 6 | switch v := i.(type) { 7 | case int: 8 | fmt.Println("int type:", v) 9 | case string, fmt.Stringer: 10 | fmt.Println("string type:", v) 11 | default: 12 | fmt.Println("unknown type:", v) 13 | } 14 | } 15 | 16 | func main() { 17 | do(21) 18 | do("hello") 19 | do(true) 20 | } 21 | -------------------------------------------------------------------------------- /lessons/interfaces/type_switch_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type fooer interface{ foo() } 6 | type barer interface{ bar() } 7 | type foobarer interface { 8 | foo() 9 | bar() 10 | } 11 | 12 | type thing struct{} 13 | 14 | func (t *thing) foo() {} 15 | func (t *thing) bar() {} 16 | 17 | var i foobarer = &thing{} 18 | 19 | func main() { 20 | switch v := i.(type) { 21 | case fooer: 22 | fmt.Println("fooer:", v) 23 | case barer: 24 | fmt.Println("barer:", v) 25 | case foobarer: 26 | fmt.Println("foobarer:", v) 27 | default: 28 | panic("none of them") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lessons/maps/big_map/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func printAllocs() { 9 | var m runtime.MemStats 10 | runtime.ReadMemStats(&m) 11 | fmt.Printf("%d MB\n", m.Alloc/1024/1024) 12 | } 13 | 14 | func main() { 15 | printAllocs() 16 | data := make(map[int][128]byte) // try to use 129 17 | printAllocs() 18 | 19 | for i := 0; i < 1_000_000; i++ { 20 | data[i] = [128]byte{} 21 | } 22 | 23 | printAllocs() 24 | 25 | for i := 0; i < 1_000_000; i++ { 26 | delete(data, i) 27 | } 28 | 29 | runtime.GC() 30 | printAllocs() 31 | runtime.KeepAlive(data) 32 | } 33 | -------------------------------------------------------------------------------- /lessons/maps/bucket_structure/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | type bucketV1 struct { 9 | key int8 10 | value int64 11 | } 12 | 13 | type bucketV2 struct { 14 | keys [8]int8 15 | values [8]int64 16 | } 17 | 18 | func main() { 19 | fmt.Println("bucketsV1:", unsafe.Sizeof([8]bucketV1{})) 20 | fmt.Println("bucketsV2:", unsafe.Sizeof(bucketV2{})) 21 | } 22 | -------------------------------------------------------------------------------- /lessons/maps/comparable_keys/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | data := map[interface{}]int{ 5 | "a": 1, 6 | 2: 2, 7 | } 8 | 9 | data[[]int{}] = 3 10 | data[func() {}] = 4 11 | } 12 | -------------------------------------------------------------------------------- /lessons/maps/delete_during_iteration/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | data := map[string]int{"foo": 0, "bar": 1, "baz": 2} 7 | for key := range data { 8 | if key == "foo" { 9 | delete(data, "bar") 10 | } 11 | if key == "bar" { 12 | delete(data, "foo") 13 | } 14 | } 15 | 16 | fmt.Println(data) 17 | } 18 | -------------------------------------------------------------------------------- /lessons/maps/element_value_address/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | data := map[int]int{0: 1} 5 | _ = &data[0] 6 | } 7 | -------------------------------------------------------------------------------- /lessons/maps/hash_function/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "hash/maphash" 6 | ) 7 | 8 | func main() { 9 | var h1 maphash.Hash 10 | h1.WriteString("hello") 11 | fmt.Println(h1.Sum64(), h1.Seed()) // random hash seed 12 | 13 | var h2 maphash.Hash 14 | h2.WriteString("hello") 15 | fmt.Println(h2.Sum64(), h2.Seed()) // random hash seed 16 | 17 | var h3 maphash.Hash 18 | h3.SetSeed(h2.Seed()) 19 | h3.WriteString("hello") 20 | fmt.Println(h3.Sum64(), h3.Seed()) // hash seed from h2 21 | } 22 | -------------------------------------------------------------------------------- /lessons/maps/iteration_order/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | data := map[int]struct{}{ 7 | 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 8 | } 9 | 10 | for key := range data { 11 | fmt.Print(key, " ") 12 | } 13 | 14 | fmt.Println() 15 | fmt.Println(data) 16 | } 17 | -------------------------------------------------------------------------------- /lessons/maps/map_clearing/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // remove all elements 7 | first := map[int]int{1: 1, 2: 2, 3: 3} 8 | first = nil 9 | fmt.Println(first, " : ", len(first)) 10 | 11 | // keep allocated memory 12 | second := map[int]int{1: 1, 2: 2, 3: 3} 13 | for key := range second { 14 | delete(second, key) 15 | } 16 | fmt.Println(second, " : ", len(second)) 17 | 18 | // keep allocated memory 19 | third := map[int]int{1: 1, 2: 2, 3: 3} 20 | clear(third) 21 | fmt.Println(third, " : ", len(third)) 22 | } 23 | -------------------------------------------------------------------------------- /lessons/maps/map_empty_assign/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | m := make(map[string]int, 3) 5 | x := len(m) 6 | 7 | m["Go"] = m["Go"] 8 | 9 | y := len(m) 10 | println(x, y) 11 | } 12 | -------------------------------------------------------------------------------- /lessons/maps/map_operations/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func readFromNilMap() { 4 | var data map[int]int 5 | _ = data[100] 6 | } 7 | 8 | func deleteFromNilMap() { 9 | var data map[int]int 10 | delete(data, 100) 11 | } 12 | 13 | func writeToNilMap() { 14 | var data map[int]int 15 | data[100] = 100 16 | } 17 | 18 | func rangeByNilMap() { 19 | var data map[int]int 20 | for range data { 21 | } 22 | } 23 | 24 | func rewriteExistingKey() { 25 | data := make(map[int]int) 26 | data[100] = 500 27 | data[100] = 1000 28 | } 29 | 30 | func deleteNonExistingKey() { 31 | data := make(map[int]int) 32 | delete(data, 100) 33 | } 34 | 35 | func main() { 36 | } 37 | -------------------------------------------------------------------------------- /lessons/maps/map_performance/performance_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | // go test -bench=. performance_test.go 6 | 7 | func BenchmarkWithSlice(b *testing.B) { 8 | slice := []int{1, 2, 3} 9 | for i := 0; i < b.N; i++ { 10 | value := slice[1] 11 | slice[1] = value 12 | } 13 | } 14 | 15 | func BenchmarkWithHashTable(b *testing.B) { 16 | table := map[int]int{0: 1, 1: 2, 2: 3} 17 | for i := 0; i < b.N; i++ { 18 | value := table[1] 19 | table[1] = value 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lessons/maps/map_with_float/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var value1 float32 = 0.3 7 | var value2 float32 = 0.6 8 | data := make(map[float32]struct{}) 9 | data[value1+value2] = struct{}{} 10 | 11 | var result float32 = 0.9 12 | _, found := data[result] 13 | fmt.Println(found) 14 | } 15 | -------------------------------------------------------------------------------- /lessons/maps/map_with_function_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func set(data map[int]int, key, value int) { 6 | data[key] = value 7 | } 8 | 9 | func main() { 10 | data := make(map[int]int) 11 | fmt.Println(data) 12 | set(data, 100, 500) 13 | fmt.Println(data) 14 | } 15 | -------------------------------------------------------------------------------- /lessons/maps/map_with_function_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func change(data map[int]int) { 6 | data = map[int]int{2: 20} 7 | } 8 | 9 | func main() { 10 | data := map[int]int{1: 10} 11 | fmt.Println(data) 12 | change(data) 13 | fmt.Println(data) 14 | } 15 | -------------------------------------------------------------------------------- /lessons/maps/mapaccess/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | data := map[int]int{100: 10000} 5 | value := data[100] 6 | _ = value 7 | 8 | // under hood 9 | // pk := unsafe.Pointer(&key) 10 | // pv := runtime.mapaccess1(typeOf(data), data, pk) 11 | // value := *(*int)(pv) 12 | } 13 | -------------------------------------------------------------------------------- /lessons/maps/range_by_map/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | data := map[int]int{1: 1, 2: 2, 3: 3} 7 | for _, value := range data { 8 | value = 1000 9 | _ = value 10 | } 11 | 12 | fmt.Println(data) 13 | } 14 | -------------------------------------------------------------------------------- /lessons/maps/update_during_iteration/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Need to show solution with maps.Clone 6 | 7 | func main() { 8 | data := map[int]struct{}{ 9 | 0: {}, 10 | 1: {}, 11 | 2: {}, 12 | } 13 | 14 | for key := range data { 15 | data[10+key] = struct{}{} 16 | } 17 | 18 | for key := range data { 19 | fmt.Print(key) 20 | fmt.Print(" ") 21 | } 22 | 23 | fmt.Println() 24 | fmt.Println(data) 25 | } 26 | -------------------------------------------------------------------------------- /lessons/maps/update_value/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type client struct { 4 | name string 5 | surname string 6 | } 7 | 8 | func updateSurname(data map[int]client, id int, surname string) { 9 | object := data[id] // copy 10 | object.surname = surname 11 | data[id] = object // copy 12 | 13 | // data[id].surname = surname -> compilation error 14 | } 15 | 16 | func updateSurnameByPointer(data map[int]*client, id int, surname string) { 17 | data[id].surname = surname 18 | } 19 | 20 | func updateSurnamesSlice(data map[int][]string, id int, surname string) { 21 | data[id][5] = surname 22 | } 23 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/access_by_index/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | const elemSize = unsafe.Sizeof(int32(0)) // 4 bytes 10 | array := [...]int32{1, 2, 3} 11 | pointer := unsafe.Pointer(&array) 12 | 13 | first := *(*int32)(unsafe.Add(pointer, 0*elemSize)) // => data2[0] 14 | second := *(*int32)(unsafe.Add(pointer, 1*elemSize)) // => data2[1] 15 | third := *(*int32)(unsafe.Add(pointer, 2*elemSize)) // => data2[2] 16 | 17 | dangerous1 := *(*int32)(unsafe.Add(pointer, -1)) // => data2[-1] 18 | dangerous2 := *(*int32)(unsafe.Add(pointer, 3)) // => data2[3] 19 | 20 | fmt.Println("correct:", first, second, third) 21 | fmt.Println("dangeroues:", dangerous1, dangerous2) 22 | } 23 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/array_moving/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | //go:noinline 9 | func allocation(index int) byte { 10 | var data [1 << 20]byte 11 | return data[index] 12 | } 13 | 14 | func main() { 15 | var array [10]int 16 | address := (uintptr)(unsafe.Pointer(&array)) 17 | fmt.Println("#1 array address:", address) 18 | 19 | allocation(100) 20 | 21 | address = (uintptr)(unsafe.Pointer(&array)) 22 | fmt.Println("#2 array address:", address) 23 | } 24 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/arrays_allocation_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // go build -gcflags='-m' . | grep escape 4 | 5 | func main() { 6 | var arrayWithStack [10 << 20]int8 7 | _ = arrayWithStack 8 | 9 | var arrayWithHeap [10<<20 + 1]int8 10 | _ = arrayWithHeap 11 | } 12 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/arrays_allocation_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //go:noinline 4 | func allocation() *[10]int { 5 | var data [10]int 6 | return &data 7 | } 8 | 9 | func main() { 10 | _ = allocation() 11 | } 12 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/arrays_with_different_type/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | data1 := [3]int{1, 2, 3} 5 | data2 := [2]int{1, 2} 6 | data1 = data2 // compliation error 7 | } 8 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/bce_absence/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // go run -gcflags="-d=ssa/check_bce" main.go 4 | 5 | func fn1(data []int, check func(int) bool) []int { 6 | var idx = 0 7 | for _, value := range data { 8 | if check(value) { 9 | data[idx] = value // Found IsInBounds 10 | idx++ 11 | } 12 | } 13 | 14 | return data[:idx] // Found IsSliceInBounds 15 | } 16 | 17 | func fn2(lhs, rhs []byte) { 18 | for idx := range min(len(lhs), len(rhs)) { 19 | _ = lhs[idx] // Found IsInBounds 20 | _ = rhs[idx] // Found IsInBounds 21 | } 22 | } 23 | 24 | func fn3(data [256]byte) { 25 | for idx := 0; idx < 128; idx++ { 26 | _ = data[2*idx] // Found IsInBounds 27 | } 28 | } 29 | 30 | func main() {} 31 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/bce_optimization_3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // go test -gcflags="-d=ssa/check_bce" -bench=. bench_test.go 4 | 5 | func sum1(values []int, size int) int { 6 | sum := 0 7 | for i := 0; i < size; i++ { 8 | sum += values[i] 9 | } 10 | 11 | return sum 12 | } 13 | 14 | func sum2(values []int, size int) int { 15 | _ = values[size-1] // for BCE 16 | 17 | sum := 0 18 | for i := 0; i < size-1; i++ { 19 | sum += values[i] 20 | } 21 | 22 | return sum 23 | } 24 | 25 | func main() { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/bce_presence/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // go run -gcflags="-d=ssa/check_bce" main.go 4 | 5 | func fn1(s []int) { 6 | for i := range s { 7 | _ = s[i] 8 | _ = s[i:] 9 | _ = s[:i+1] 10 | } 11 | } 12 | 13 | func fn2(s []int) { 14 | for i := 0; i < len(s); i++ { 15 | _ = s[i] 16 | _ = s[i:] 17 | _ = s[:i+1] 18 | } 19 | } 20 | 21 | func main() {} 22 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/check_length/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Need to show solution 4 | 5 | func handleOperations(id string) { 6 | operations := getOperations(id) 7 | if operations == nil { 8 | // handling... 9 | } 10 | } 11 | 12 | func getOperations(id string) []float32 { 13 | opearations := []float32{} 14 | if id == "" { 15 | return opearations 16 | } 17 | 18 | // adding operations... 19 | return opearations 20 | } 21 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/collection_optimization/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func printAllocs() { 9 | var m runtime.MemStats 10 | runtime.ReadMemStats(&m) 11 | fmt.Printf("%d MB\n", m.Alloc/1024/1024) 12 | } 13 | 14 | func main() { 15 | data := make([]byte, 1<<31) 16 | 17 | printAllocs() 18 | runtime.GC() 19 | printAllocs() 20 | 21 | fmt.Println(len(data)) 22 | } 23 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/copy_implementation/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func cp(dst, src []int) { 6 | minLength := min(len(dst), len(src)) 7 | for idx := 0; idx < minLength; idx++ { 8 | dst[idx] = src[idx] 9 | } 10 | } 11 | 12 | func main() { 13 | src := []int{1, 2, 3, 4, 5} 14 | dst := make([]int, 3) 15 | copy(dst, src) 16 | 17 | fmt.Println("src", src) 18 | fmt.Println("dst", dst) 19 | } 20 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/copy_slice/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | src := []int{1, 2, 3} 7 | var dst []int 8 | copy(dst, src) 9 | fmt.Println("copied:", dst) 10 | } 11 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/dangerous_append/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | data := make([]int, 4, 5) 7 | copy := append(data, 5) 8 | 9 | fmt.Println(data) 10 | //fmt.Println(data[:5]) 11 | fmt.Println(copy) 12 | 13 | /* 14 | data := make([]int, 5, 5) 15 | copy := append(data, 5) 16 | 17 | fmt.Println(data) 18 | fmt.Println(copy) 19 | */ 20 | } 21 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/different_range_by_array/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | data := [...]int{1, 2, 3} 7 | for value := range data { // copy of array 8 | fmt.Println(value) 9 | } 10 | 11 | for value := range &data { // not a copy of array 12 | fmt.Println(value) 13 | } 14 | 15 | for value := range data[:] { // not a copy of array 16 | fmt.Println(value) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/dirty_slice/creation_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | "unsafe" 7 | ) 8 | 9 | // go test -bench=. creation_test.go 10 | 11 | func makeDirty(size int) []byte { 12 | var sb strings.Builder 13 | sb.Grow(size) 14 | 15 | pointer := unsafe.StringData(sb.String()) 16 | return unsafe.Slice(pointer, size) 17 | } 18 | 19 | var Result []byte 20 | 21 | func BenchmarkMake(b *testing.B) { 22 | for i := 0; i < b.N; i++ { 23 | Result = make([]byte, 0, 10<<20) 24 | } 25 | } 26 | 27 | func BenchmarkMakeDirty(b *testing.B) { 28 | for i := 0; i < b.N; i++ { 29 | Result = makeDirty(10 << 20) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/endless_range/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | data := []int{0, 1, 2} 7 | for range data { 8 | data = append(data, 10) 9 | fmt.Println("iteration") 10 | } 11 | 12 | /* 13 | data := []int{0, 1, 2} 14 | for i := 0; i < len(data); i++ { 15 | data = append(data, 10) 16 | fmt.Println("iteration") 17 | } 18 | */ 19 | } 20 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/incorrect_range_by_array/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | values := [...]int{100, 200, 300} 10 | 11 | // also actual for slices 12 | for idx, value := range values { 13 | value += 50 14 | fmt.Println("#1:", unsafe.Pointer(&value), "#2:", unsafe.Pointer(&values[idx])) 15 | } 16 | 17 | fmt.Println("values:", values) 18 | } 19 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/iteration_by_pointer_to_array/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var array *[4]int // = nil 7 | 8 | fmt.Println("length =", len(array)) 9 | fmt.Println("capacity =", cap(array)) 10 | 11 | for idx := range array { // ok 12 | fmt.Println(idx) 13 | } 14 | 15 | for idx, value := range array { // panic 16 | fmt.Println(idx, value) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/memclr/clear_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // go test -bench=. clear_test.go 8 | 9 | func BenchmarkClearWithFive(b *testing.B) { 10 | data := make([]int, 10*1024) 11 | for i := 0; i < b.N; i++ { 12 | for idx := range data { 13 | data[idx] = 5 14 | } 15 | } 16 | } 17 | 18 | func BenchmarkClearWithZero(b *testing.B) { 19 | data := make([]int, 10*1024) 20 | for i := 0; i < b.N; i++ { 21 | for idx := range data { 22 | data[idx] = 0 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/pointer_to_slice_element/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func printAllocs() { 9 | var m runtime.MemStats 10 | runtime.ReadMemStats(&m) 11 | fmt.Printf("%d MB\n", m.Alloc/1024/1024) 12 | } 13 | 14 | func FindElement(numbers []int, target int) *int { 15 | for idx := range numbers { 16 | if numbers[idx] == target { 17 | return &numbers[idx] 18 | } 19 | } 20 | 21 | return nil 22 | } 23 | 24 | func main() { 25 | var numbers = make([]int, 1<<30) 26 | pointer := FindElement(numbers, 0) 27 | _ = pointer 28 | 29 | printAllocs() 30 | runtime.GC() 31 | printAllocs() 32 | 33 | runtime.KeepAlive(pointer) 34 | } 35 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/range_task/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var x = []string{"A", "M", "C"} 5 | 6 | for i, s := range x { 7 | print(i, s, ",") 8 | x[i+1] = "M" 9 | x = append(x, "Z") 10 | x[i+1] = "Z" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/resize_slice/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | data := make([]int, 3, 6) // len = 3, cap = 6 7 | 8 | // fmt.Println(data[4]) // panic 9 | 10 | data = data[:6] // len = 6, cap = 6 11 | 12 | fmt.Println(data[4]) 13 | } 14 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/slice_increasing/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | slice := make([]int, 0, 3) 5 | println("slice:", slice, "- slice header address:", &slice) 6 | 7 | slice = append(slice, 1, 2, 3) 8 | println("slice full capacity:", slice) 9 | 10 | slice = append(slice, 4) 11 | println("slice after exceed capacity:", slice) 12 | } 13 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/slice_of_slices/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | type Data struct { 9 | values []byte 10 | } 11 | 12 | func printAllocs() { 13 | var m runtime.MemStats 14 | runtime.ReadMemStats(&m) 15 | fmt.Printf("%d MB\n", m.Alloc/1024/1024) 16 | } 17 | 18 | func GetData() []Data { 19 | data := make([]Data, 1000) // ~24KB 20 | 21 | for i := 0; i < len(data); i++ { 22 | data[i] = Data{ 23 | values: make([]byte, 1<<20), 24 | } 25 | } 26 | 27 | clear(data[2:]) 28 | return data[:2] 29 | } 30 | 31 | func main() { 32 | data := GetData() 33 | 34 | printAllocs() 35 | runtime.GC() 36 | printAllocs() 37 | 38 | runtime.KeepAlive(data) 39 | } 40 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/slice_type_transformation/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "unsafe" 5 | ) 6 | 7 | type slice struct { 8 | data unsafe.Pointer 9 | len int 10 | cap int 11 | } 12 | 13 | func Transform(data []byte) []int { 14 | sliceData := unsafe.Pointer(&data[0]) 15 | sizeType := int(unsafe.Sizeof(0)) 16 | length := len(data) / sizeType 17 | 18 | var result []int 19 | resultPtr := (*slice)(unsafe.Pointer(&result)) 20 | resultPtr.data = sliceData 21 | resultPtr.len = length 22 | resultPtr.cap = length 23 | 24 | return result 25 | } 26 | 27 | func main() { 28 | data := make([]byte, 800) 29 | converted := Transform(data) 30 | _ = converted 31 | } 32 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/slice_with_function_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | data := []int{1, 2, 3, 4} // len = 4, cap = 4 7 | 8 | fmt.Println("initial slice: ", data) 9 | process1(data) 10 | fmt.Println("after process1:", data) 11 | process2(data) 12 | fmt.Println("after process2:", data) 13 | } 14 | 15 | func process1(data []int) { 16 | data[2] = 5 17 | } 18 | 19 | func process2(data []int) { 20 | data = append(data, 6) 21 | fmt.Println("len:", len(data), "cap:", cap(data)) 22 | } 23 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/slice_with_function_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | data := make([]int, 3, 6) 7 | 8 | fmt.Println("initial slice:", data) 9 | process(data) 10 | fmt.Println("after process:", data) 11 | fmt.Println("after process:", data[:4]) 12 | } 13 | 14 | func process(data []int) { 15 | data = append(data, 5) 16 | } 17 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/slices_allocation/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // go build -gcflags='-m' . |& grep escape 4 | 5 | func main() { 6 | sliceWithStack := make([]byte, 64<<10) 7 | _ = sliceWithStack 8 | 9 | size := 10 10 | sliceWithHeap1 := make([]byte, size) 11 | _ = sliceWithHeap1 12 | 13 | sliceWithHeap2 := make([]byte, 64<<10+1) 14 | _ = sliceWithHeap2 15 | 16 | // unknown ... 17 | var sliceSpecialCase = []byte{1 << 30: 1} 18 | _ = sliceSpecialCase 19 | } 20 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/slices_comparison/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | data1 := []int{1, 2, 3, 4, 5} 10 | data2 := []int{1, 2, 3, 4, 5} 11 | 12 | // data1 == data2 -> compilation error 13 | 14 | fmt.Println("equal:", reflect.DeepEqual(data1, data2)) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/slices_comparison_recursive/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type client struct { 9 | identifier string 10 | operations []int 11 | } 12 | 13 | func main() { 14 | data1 := make([]client, 10) 15 | data2 := make([]client, 10) 16 | 17 | data1[1].operations = append(data1[1].operations, 10) 18 | fmt.Println("equal:", reflect.DeepEqual(data1, data2)) 19 | } 20 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/slices_to_array_pointer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | slice := make([]int, 3, 6) 9 | array := (*[3]int)(slice) 10 | 11 | slice[0] = 10 12 | 13 | fmt.Println("slice = ", slice, len(slice), cap(slice)) 14 | fmt.Println("array =", array, len(array), cap(array)) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/slices_to_arrays/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | slice := make([]int, 3, 6) 9 | array := [3]int(slice[:3]) 10 | 11 | slice[0] = 10 12 | 13 | fmt.Println("slice =", slice, len(slice), cap(slice)) 14 | fmt.Println("array =", array, len(array), cap(array)) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/slices_and_arrays/slicing_task/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | a := [...]int{0, 1, 2, 3} 7 | x := a[:1] 8 | y := a[2:] 9 | 10 | x = append(x, y...) 11 | x = append(x, y...) 12 | 13 | fmt.Println("a:", a) 14 | fmt.Println("x:", x) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/strings/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Balun-courses/deep_go/aacfeb63b810479f98cebcaa16a444e3c8710ee0/lessons/strings/.DS_Store -------------------------------------------------------------------------------- /lessons/strings/allocations/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | var result string 9 | 10 | func Concat(b *testing.B) { 11 | for i := 0; i < b.N; i++ { 12 | result = "Hello" + " world" 13 | } 14 | } 15 | 16 | func Conversion(b *testing.B) { 17 | for i := 0; i < b.N; i++ { 18 | result = string([]byte("Hello world")) 19 | } 20 | } 21 | 22 | func main() { 23 | b1 := testing.Benchmark(Concat) 24 | fmt.Println("b1:", b1.AllocsPerOp()) // 0 25 | fmt.Println("b1:", b1.AllocedBytesPerOp()) // 0 26 | 27 | b2 := testing.Benchmark(Conversion) 28 | fmt.Println("b2:", b2.AllocsPerOp()) // 1 29 | fmt.Println("b2:", b2.AllocedBytesPerOp()) // 16 30 | } 31 | -------------------------------------------------------------------------------- /lessons/strings/append_and_copy/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | hello := []byte("Hello ") 7 | world := "world!" 8 | 9 | helloWorld1 := append(hello, world...) // sugar 10 | fmt.Println(string(helloWorld1)) 11 | 12 | helloWorld2 := make([]byte, len(hello)+len(world)) 13 | copy(helloWorld2, hello) 14 | 15 | copy(helloWorld2[len(hello):], world) // sugar 16 | fmt.Println(string(helloWorld2)) 17 | } 18 | -------------------------------------------------------------------------------- /lessons/strings/byte_address/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | str := "hello" 10 | pointer := unsafe.StringData(str[4:5]) 11 | fmt.Println(pointer, string(*pointer)) 12 | } 13 | -------------------------------------------------------------------------------- /lessons/strings/byte_slice_to_string/comparison_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | "unsafe" 6 | ) 7 | 8 | // go test -bench=. -benchmem comparison_test.go 9 | 10 | func Convert(data []byte) string { 11 | if len(data) == 0 { 12 | return "" 13 | } 14 | 15 | return unsafe.String(unsafe.SliceData(data), len(data)) 16 | } 17 | 18 | var Result string 19 | 20 | func BenchmarkConvertion(b *testing.B) { 21 | slice := []byte("Hello world!!!") 22 | for i := 0; i < b.N; i++ { 23 | Result = string(slice) 24 | } 25 | } 26 | 27 | func BenchmarkUnsafeConvertion(b *testing.B) { 28 | slice := []byte("Hello world!!!") 29 | for i := 0; i < b.N; i++ { 30 | Result = Convert(slice) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lessons/strings/const_strings/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "unsafe" 4 | 5 | func main() { 6 | const str1 string = "example" 7 | const str2 string = "example" 8 | const str3 string = "another example" 9 | 10 | println(unsafe.StringData(str1)) 11 | println(unsafe.StringData(str2)) 12 | println(unsafe.StringData(str3)) 13 | } 14 | -------------------------------------------------------------------------------- /lessons/strings/conversion_deprecated/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | /* 9 | type SliceHeader struct { 10 | Data unsafe.Pointer 11 | Len int 12 | Cap int 13 | } 14 | 15 | type StringHeader struct { 16 | Data unsafe.Pointer 17 | Len int 18 | } 19 | */ 20 | 21 | func ToStringDeprecated(data []byte) string { 22 | return *(*string)(unsafe.Pointer(&data)) 23 | } 24 | 25 | func main() { 26 | data := []byte{'h', 'e', 'l', 'l', 'o'} 27 | str := ToStringDeprecated(data) 28 | fmt.Println(str) 29 | } 30 | -------------------------------------------------------------------------------- /lessons/strings/encodings/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // incorrect code points 7 | data := []rune{0x0011FFFF, 0x0012FFFF} 8 | str := string(data) 9 | 10 | fmt.Println(str) 11 | } 12 | -------------------------------------------------------------------------------- /lessons/strings/interpreted_and_raw_strings/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | interpreted := "\nHello\nworld!\n" 7 | raw := `\nHello\nworld!\n` 8 | 9 | fmt.Println(interpreted) 10 | fmt.Println(raw) 11 | 12 | interpretedData := []byte("\n") 13 | rawData := []byte(`\n`) 14 | 15 | fmt.Println("interpretedData:", interpretedData) 16 | fmt.Println("rawData:", rawData) 17 | } 18 | -------------------------------------------------------------------------------- /lessons/strings/letter_frequencies/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func CalculateFrequencies(str string) { 6 | frequencies := [26]int{} 7 | for _, letter := range str { 8 | letterIdx := letter - 'a' 9 | frequencies[letterIdx]++ 10 | } 11 | 12 | for letterIdx, frequency := range frequencies { 13 | if frequency != 0 { 14 | letter := 'a' + letterIdx 15 | fmt.Printf("%c = %d\n", letter, frequency) 16 | } 17 | } 18 | } 19 | 20 | func main() { 21 | CalculateFrequencies("aabaacdb") 22 | } 23 | -------------------------------------------------------------------------------- /lessons/strings/letter_order/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println('w' - 'a') // 119 - 97 7 | fmt.Println('o' - 'a') // 111 - 97 8 | } 9 | -------------------------------------------------------------------------------- /lessons/strings/mutate_string_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | data := []byte("Hello world") 10 | strData := unsafe.String(unsafe.SliceData(data), len(data)) 11 | 12 | fmt.Println(strData) 13 | data[0] = 'W' 14 | fmt.Println(strData) 15 | } 16 | -------------------------------------------------------------------------------- /lessons/strings/mutate_string_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "unsafe" 4 | 5 | func action() {} 6 | 7 | func main() { 8 | var str = "go" 9 | newStr := str + "-go" 10 | 11 | strData := unsafe.StringData(str) 12 | newStrData := unsafe.StringData(newStr) 13 | 14 | println("action:", action) 15 | println("strData:", strData) 16 | println("newStrData:", newStrData) 17 | 18 | slice := unsafe.Slice(strData, len(str)) 19 | newSlice := unsafe.Slice(newStrData, len(newStr)) 20 | 21 | newSlice[0] = 'G' 22 | println("newStr:", newStr) 23 | 24 | slice[0] = 'G' 25 | println("str:", str) 26 | } 27 | -------------------------------------------------------------------------------- /lessons/strings/range_ascii_vs_utf8/speed_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // go test -bench=. speed_test.go 8 | 9 | func BenchmarkByRangeBytes(b *testing.B) { 10 | text := []byte("aaaabbbbccccddddeeeeffff") 11 | 12 | b.ResetTimer() 13 | for i := 0; i < b.N; i++ { 14 | for _, _ = range text { 15 | } 16 | } 17 | } 18 | 19 | func BenchmarkByRangeStringUTF8(b *testing.B) { 20 | text := "aaaabbbbccccddddeeeeffff" 21 | 22 | b.ResetTimer() 23 | for i := 0; i < b.N; i++ { 24 | for _, _ = range text { 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lessons/strings/runes_to_bytes/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "unicode/utf8" 6 | ) 7 | 8 | func Runes2Bytes(rs []rune) []byte { 9 | n := 0 10 | for _, r := range rs { 11 | n += utf8.RuneLen(r) 12 | } 13 | 14 | n, bs := 0, make([]byte, n) 15 | for _, r := range rs { 16 | n += utf8.EncodeRune(bs[n:], r) 17 | } 18 | 19 | return bs 20 | } 21 | 22 | func main() { 23 | s := "Hello world!!!" 24 | 25 | bs := []byte(s) // string -> []byte 26 | s = string(bs) // []byte -> string 27 | 28 | rs := []rune(s) // string -> []rune 29 | s = string(rs) // []rune -> string 30 | 31 | rs = bytes.Runes(bs) // []byte -> []rune 32 | bs = Runes2Bytes(rs) // []rune -> []byte 33 | } 34 | -------------------------------------------------------------------------------- /lessons/strings/speed_comparison/comparison_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | // go test -bench=. comparison_test.go 6 | 7 | func BenchmarkComparison(b *testing.B) { 8 | bs := make([]byte, 1<<26) 9 | s0 := string(bs) 10 | s1 := string(bs) 11 | 12 | b.ResetTimer() 13 | for i := 0; i < b.N; i++ { 14 | _ = s0 == s1 15 | } 16 | } 17 | 18 | func BenchmarkComparisonOptimized(b *testing.B) { 19 | bs := make([]byte, 1<<26) 20 | s0 := string(bs) 21 | s1 := s0 22 | 23 | b.ResetTimer() 24 | for i := 0; i < b.N; i++ { 25 | _ = s0 == s1 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lessons/strings/string_builder_copy/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "strings" 4 | 5 | func firstWay() { 6 | old := strings.Builder{} 7 | // manipulating with old.. 8 | new := old 9 | _ = new 10 | } 11 | 12 | func secondWay() { 13 | old := strings.Builder{} 14 | // manipulating with old.. 15 | new := strings.Builder{} 16 | new.WriteString(old.String()) 17 | _ = new 18 | } 19 | -------------------------------------------------------------------------------- /lessons/strings/string_implementation/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var table = map[uint8]byte{ 6 | 0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 7 | 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 8 | 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 9 | 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 10 | 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 11 | 25: 'z', 12 | } 13 | 14 | func printText(text []uint8) { 15 | for _, codeNumber := range text { 16 | symbol, found := table[codeNumber] 17 | if !found { 18 | fmt.Printf("#incorrect code symbol: %d\n", codeNumber) 19 | return 20 | } 21 | 22 | fmt.Printf("%q", symbol) 23 | } 24 | } 25 | 26 | func main() { 27 | text := []uint8{7, 4, 11, 11, 14} 28 | printText(text) 29 | } 30 | -------------------------------------------------------------------------------- /lessons/strings/string_len/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | str1 := "hello" 7 | str2 := "汉hello" 8 | 9 | fmt.Println(len(str1), len(str2)) 10 | } 11 | -------------------------------------------------------------------------------- /lessons/strings/string_to_byte_slice/comparison_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | "unsafe" 6 | ) 7 | 8 | // go test -bench=. -benchmem comparison_test.go 9 | 10 | func Convert(str string) []byte { 11 | if len(str) == 0 { 12 | return nil 13 | } 14 | 15 | return unsafe.Slice(unsafe.StringData(str), len(str)) 16 | } 17 | 18 | var Result []byte 19 | 20 | func BenchmarkConvertion(b *testing.B) { 21 | str := "Hello world!!!" 22 | for i := 0; i < b.N; i++ { 23 | Result = []byte(str) 24 | } 25 | } 26 | 27 | func BenchmarkUnsafeConvertion(b *testing.B) { 28 | str := "Hello world!!!" 29 | for i := 0; i < b.N; i++ { 30 | Result = Convert(str) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lessons/strings/strings_operations/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func writeToStringSymbol() { 4 | str := "hello" 5 | // str[0] = 'H' -> compilation error 6 | _ = str 7 | } 8 | 9 | func rewriteString() { 10 | str := "hello" 11 | str = "world" 12 | // str[0] = 'H' -> compilation error 13 | _ = str 14 | } 15 | 16 | func takeStringSymbolAddress() { 17 | str := "hello" 18 | // pointer := &str[0] -> compilation error 19 | _ = str 20 | } 21 | 22 | func slicingString() { 23 | /* 24 | const str = "hello" 25 | _ = str[0:10] -> compilation error 26 | */ 27 | } 28 | -------------------------------------------------------------------------------- /lessons/strings/strings_range/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | text := "Sr, привет 世界" 7 | for idx, symbol := range text { // range []rune(text) 8 | fmt.Printf("%d-%c ", idx, symbol) 9 | } 10 | 11 | fmt.Println() 12 | for i := 0; i < len(text); i++ { // range []byte(text) 13 | fmt.Printf("%d-%c ", i, text[i]) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lessons/strings/substring/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | str := "字Hello" 7 | substr := str[:6] 8 | fmt.Println(substr) 9 | } 10 | -------------------------------------------------------------------------------- /lessons/strings/trim_right_and_trim_suffix/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func main() { 9 | str := "oxo123oxo" 10 | fmt.Println("TrimRight:", strings.TrimRight(str, "xo")) 11 | fmt.Println("TrimSuffix:", strings.TrimSuffix(str, "xo")) 12 | // also for strings.TrimLeft() and strings.TrimPrefix() 13 | } 14 | -------------------------------------------------------------------------------- /lessons/structs/alignment_functions/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | type data struct { 9 | aaa bool 10 | bbb int32 11 | ccc bool 12 | } 13 | 14 | func main() { 15 | d := data{} 16 | fmt.Println(unsafe.Offsetof(d.ccc)) 17 | 18 | fmt.Println(unsafe.Alignof(d)) 19 | } 20 | -------------------------------------------------------------------------------- /lessons/structs/ambiguous_selectors/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Derived1 struct { 4 | values []int 5 | } 6 | 7 | func (d Derived1) Print() {} 8 | 9 | type Derived2 struct { 10 | values []int 11 | } 12 | 13 | func (d Derived2) Print() {} 14 | 15 | type Base struct { 16 | Derived1 17 | Derived2 18 | } 19 | 20 | func main() { 21 | var base Base 22 | // _ = base.values 23 | // base.Print() 24 | 25 | base.Derived1.values = nil 26 | base.Derived2.values = nil 27 | 28 | base.Derived1.Print() 29 | base.Derived2.Print() 30 | } 31 | -------------------------------------------------------------------------------- /lessons/structs/anonymous_struct/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var book = struct { 5 | author struct { 6 | name string 7 | surname string 8 | } 9 | title string 10 | }{ 11 | author: struct { 12 | name string 13 | surname string 14 | }{ 15 | name: "Name", 16 | surname: "Surname", 17 | }, 18 | title: "Title", 19 | } 20 | 21 | _ = book 22 | } 23 | -------------------------------------------------------------------------------- /lessons/structs/bind_receiver/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Data struct { 6 | value int 7 | } 8 | 9 | func (d Data) Value1() int { 10 | return d.value 11 | } 12 | 13 | func (d *Data) Value2() int { 14 | return d.value 15 | } 16 | 17 | func main() { 18 | data := Data{100} 19 | pointer := &data 20 | 21 | value1ByData := data.Value1 22 | value1ByPointer := pointer.Value1 23 | 24 | value2ByData := data.Value2 25 | value2ByPointer := pointer.Value2 26 | 27 | data.value = 200 28 | 29 | fmt.Println("value1ByData:", value1ByData()) 30 | fmt.Println("value1ByPointer:", value1ByPointer()) 31 | fmt.Println("value2ByData:", value2ByData()) 32 | fmt.Println("value2ByPointer:", value2ByPointer()) 33 | } 34 | -------------------------------------------------------------------------------- /lessons/structs/blank_methods/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Data struct{} 4 | 5 | func (d Data) _() {} 6 | func (d Data) _() {} 7 | func (d Data) _() {} 8 | func (d Data) _() {} 9 | func (d Data) _() {} 10 | -------------------------------------------------------------------------------- /lessons/structs/check_struct_size/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "unsafe" 4 | 5 | type Data struct { 6 | id int32 7 | data [60]byte 8 | } 9 | 10 | // Describe: 11 | // - Alignof 12 | // - Offsetof 13 | 14 | var _ uintptr = unsafe.Sizeof(Data{}) - 64 15 | var _ uintptr = 64 - unsafe.Sizeof(Data{}) 16 | -------------------------------------------------------------------------------- /lessons/structs/closer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Closer struct { 4 | actios []func() 5 | } 6 | 7 | func (c *Closer) Add(action func()) { 8 | if action != nil { 9 | return 10 | } 11 | 12 | c.actios = append(c.actios, action) 13 | } 14 | 15 | func (c *Closer) Close() { 16 | for _, action := range c.actios { 17 | action() 18 | } 19 | } 20 | 21 | func main() { 22 | // code.. 23 | var closer Closer 24 | 25 | closer.Add(func() { 26 | // close connections 27 | }) 28 | 29 | closer.Add(func() { 30 | // close database 31 | }) 32 | 33 | closer.Add(func() { 34 | // close worker 35 | }) 36 | 37 | // code... 38 | 39 | closer.Close() 40 | } 41 | -------------------------------------------------------------------------------- /lessons/structs/comparison/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type client struct { 6 | id string 7 | operations []float64 8 | } 9 | 10 | func main() { 11 | client1 := client{id: "x", operations: []float64{1.}} 12 | client2 := client{id: "y", operations: []float64{1.}} 13 | fmt.Println(client1 == client2) 14 | 15 | /* 16 | var anyClient1 any = client{id: "x", operations: []float64{1.}} 17 | var anyClient2 any = client{id: "y", operations: []float64{1.}} 18 | fmt.Println(anyClient1 == anyClient2) 19 | */ 20 | } 21 | -------------------------------------------------------------------------------- /lessons/structs/comparison_benchmark/comparison_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // go test -bench=. comparison_test.go 8 | 9 | type Data1 struct { 10 | size int32 11 | values [10 << 20]byte 12 | } 13 | 14 | type Data2 struct { 15 | values [10 << 20]byte 16 | size int32 17 | } 18 | 19 | func BenchmarkComparisonData1(b *testing.B) { 20 | data1 := Data1{size: 100} 21 | data2 := Data1{size: 101} 22 | for i := 0; i < b.N; i++ { 23 | _ = data1 == data2 24 | } 25 | } 26 | 27 | func BenchmarkComparisonData2(b *testing.B) { 28 | data1 := Data2{size: 100} 29 | data2 := Data2{size: 101} 30 | for i := 0; i < b.N; i++ { 31 | _ = data1 == data2 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lessons/structs/configurable_object/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Logger struct { 4 | name string 5 | level string 6 | } 7 | 8 | func NewLogger() *Logger { 9 | return &Logger{} 10 | } 11 | 12 | func (l *Logger) WithName(name string) *Logger { 13 | l.name = name 14 | return l 15 | } 16 | 17 | func (l *Logger) WithLevel(level string) *Logger { 18 | l.level = level 19 | return l 20 | } 21 | 22 | func main() { 23 | logger1 := NewLogger() 24 | logger2 := NewLogger().WithLevel("INFO") 25 | logger3 := NewLogger().WithName("storage") 26 | 27 | _ = logger1 28 | _ = logger2 29 | _ = logger3 30 | } 31 | -------------------------------------------------------------------------------- /lessons/structs/copy_struct/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Data struct { 4 | x int 5 | y int 6 | } 7 | 8 | func main() { 9 | // 1 way 10 | data1 := Data{x: 10, y: 10} 11 | temp1 := data1 12 | _ = temp1 13 | 14 | // 2 way 15 | data2 := Data{x: 10, y: 10} 16 | var temp2 Data 17 | temp2.x = data2.x 18 | temp2.y = data2.y 19 | } 20 | -------------------------------------------------------------------------------- /lessons/structs/defer_calculating_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type data1 struct { 6 | value int 7 | } 8 | 9 | func (d data1) print() { 10 | fmt.Println("data1", d.value) 11 | } 12 | 13 | type data2 struct { 14 | value int 15 | } 16 | 17 | func (d *data2) print() { 18 | fmt.Println("data2", d.value) 19 | } 20 | 21 | func main() { 22 | d1 := data1{} 23 | defer d1.print() 24 | 25 | d2 := data2{} 26 | defer d2.print() 27 | 28 | d1.value = 100 29 | d2.value = 200 30 | } 31 | -------------------------------------------------------------------------------- /lessons/structs/defer_calculating_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Data struct{} 4 | 5 | func MakeData(pointer *int) Data { 6 | println("MakeData:", *pointer) 7 | return Data{} 8 | } 9 | 10 | func (Data) Print(pointer *int) { 11 | println("Print:", *pointer) 12 | } 13 | 14 | func main() { 15 | var value = 1 16 | var pointer = &value 17 | defer MakeData(pointer).Print(pointer) 18 | 19 | value = 2 20 | pointer = new(int) 21 | MakeData(pointer) 22 | } 23 | -------------------------------------------------------------------------------- /lessons/structs/different_receivers/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type customer1 struct { 6 | balance int 7 | } 8 | 9 | func (c customer1) add(value int) { 10 | c.balance += value 11 | } 12 | 13 | type customer2 struct { 14 | balance int 15 | } 16 | 17 | func (c *customer2) add(value int) { 18 | c.balance += value 19 | } 20 | 21 | func main() { 22 | c1 := customer1{} 23 | c1.add(100) 24 | 25 | c2 := customer2{} 26 | c2.add(100) 27 | 28 | fmt.Println(c1) 29 | fmt.Println(c2) 30 | } 31 | -------------------------------------------------------------------------------- /lessons/structs/empty_struct_size/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | type data struct{} 9 | 10 | func main() { 11 | x := &data{} 12 | y := data{} 13 | 14 | fmt.Println(unsafe.Sizeof(x)) 15 | fmt.Println(unsafe.Sizeof(y)) 16 | } 17 | -------------------------------------------------------------------------------- /lessons/structs/empty_structs/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | type empty struct{} 9 | 10 | func main() { 11 | a := struct{}{} 12 | b := struct{}{} 13 | c := empty{} 14 | d := [0]byte{} 15 | 16 | fmt.Println(unsafe.Pointer(&a)) 17 | fmt.Println(unsafe.Pointer(&b)) 18 | fmt.Println(unsafe.Pointer(&c)) 19 | fmt.Println(unsafe.Pointer(&d)) 20 | } 21 | -------------------------------------------------------------------------------- /lessons/structs/final_zero_field/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | type T1 struct { 10 | a struct{} 11 | x int64 12 | } 13 | 14 | var t1 T1 15 | fmt.Println("size:", unsafe.Sizeof(t1)) 16 | /* 17 | fmt.Println("address a:", unsafe.Pointer(&t1.a)) 18 | fmt.Println("address x:", unsafe.Pointer(&t1.x)) 19 | */ 20 | 21 | type T2 struct { 22 | x int64 23 | a struct{} 24 | } 25 | 26 | var t2 T2 27 | fmt.Println("size:", unsafe.Sizeof(t2)) 28 | /* 29 | fmt.Println("address a:", unsafe.Pointer(&t2.a)) 30 | fmt.Println("address x:", unsafe.Pointer(&t2.x)) 31 | */ 32 | } 33 | -------------------------------------------------------------------------------- /lessons/structs/implicit_method_call/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Data struct{} 6 | 7 | func (d Data) Print() { 8 | fmt.Println("data") 9 | } 10 | 11 | func main() { 12 | var data Data 13 | 14 | data.Print() 15 | (&data).Print() 16 | 17 | (Data).Print(data) 18 | (*Data).Print(&data) 19 | } 20 | -------------------------------------------------------------------------------- /lessons/structs/inheritance/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Person struct { 6 | Name string 7 | } 8 | 9 | func (p *Person) Intro() string { 10 | return p.Name 11 | } 12 | 13 | type Woman struct { 14 | Person 15 | } 16 | 17 | func (w *Woman) Intro() string { 18 | return "Mrs. " + w.Person.Intro() 19 | } 20 | 21 | func main() { 22 | woman := Woman{ 23 | Person: Person{ 24 | Name: "Ekaterina", 25 | }, 26 | } 27 | 28 | fmt.Println(woman.Intro()) 29 | fmt.Println(woman.Person.Intro()) 30 | } 31 | -------------------------------------------------------------------------------- /lessons/structs/methods_for_basic_types/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Age int 4 | 5 | func (age Age) LargerThan(other Age) bool { 6 | return age > other 7 | } 8 | 9 | type FilterFunc func(int) bool 10 | 11 | func (ff FilterFunc) Filter(value int) bool { 12 | return ff(value) 13 | } 14 | 15 | type StringSet map[string]struct{} 16 | 17 | func (ss StringSet) Has(key string) bool { 18 | _, found := ss[key] 19 | return found 20 | } 21 | 22 | func (ss StringSet) Add(key string) { 23 | ss[key] = struct{}{} 24 | } 25 | 26 | func (ss StringSet) Remove(key string) { 27 | delete(ss, key) 28 | } 29 | -------------------------------------------------------------------------------- /lessons/structs/nil_receiver/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Obect struct{} 6 | 7 | func (o *Obect) Print() { 8 | if o == nil { 9 | fmt.Println("nil") 10 | } else { 11 | fmt.Println("not nil") 12 | } 13 | } 14 | 15 | func main() { 16 | var object *Obect 17 | object.Print() 18 | } 19 | -------------------------------------------------------------------------------- /lessons/structs/optional_parameters/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Option func(*User) 4 | 5 | type User struct { 6 | Name string 7 | Surname string 8 | Email *string 9 | Phone *string 10 | Address *string 11 | } 12 | 13 | func NewUser(name string, surname string, email, phone, address *string) User { 14 | return User{ 15 | Name: name, 16 | Surname: surname, 17 | Email: email, 18 | Phone: phone, 19 | Address: address, 20 | } 21 | } 22 | 23 | func main() { 24 | email := "test@test.ru" 25 | phone := "" 26 | 27 | user1 := NewUser("Ivan", "Ivanov", &email, &phone, nil) 28 | _ = user1 29 | } 30 | -------------------------------------------------------------------------------- /lessons/structs/recursive_receiver/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type account struct { 6 | balance int 7 | } 8 | 9 | type client struct { 10 | account *account 11 | } 12 | 13 | func (c client) add(value int) { 14 | c.account.balance += value 15 | } 16 | 17 | func main() { 18 | c := client{ 19 | account: &account{}, 20 | } 21 | 22 | c.add(100) 23 | fmt.Println(c.account.balance) 24 | } 25 | -------------------------------------------------------------------------------- /lessons/structs/skipping_selectors/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type A struct { 4 | value int 5 | } 6 | 7 | func (a A) Print() {} 8 | 9 | type B struct { 10 | A 11 | } 12 | 13 | type C struct { 14 | *B 15 | } 16 | 17 | func main() { 18 | var c C = C{B: &B{A: A{value: 10}}} 19 | //var c C = C{&B{A{10}}} -> the same 20 | 21 | _ = c.B.A.value 22 | _ = c.A.value 23 | _ = c.value 24 | 25 | c.B.A.Print() 26 | c.B.Print() 27 | c.Print() 28 | } 29 | -------------------------------------------------------------------------------- /lessons/structs/struct/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Data struct { 4 | x int 5 | y int 6 | } 7 | 8 | func main() { 9 | // 1 way 10 | data1 := Data{10, 20} 11 | _ = data1 12 | 13 | // 2 way 14 | data2 := Data{x: 10, y: 20} 15 | _ = data2 16 | } 17 | -------------------------------------------------------------------------------- /lessons/structs/struct_alignment_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | type data1 struct { 9 | aaa bool 10 | bbb int32 11 | ccc bool 12 | } 13 | 14 | type data2 struct { 15 | aaa int32 16 | bbb bool 17 | ccc bool 18 | } 19 | 20 | func main() { 21 | fmt.Println(unsafe.Sizeof(data1{})) 22 | fmt.Println(unsafe.Sizeof(data2{})) 23 | 24 | /* 25 | d := data1{ 26 | aaa: true, 27 | bbb: 5, 28 | ccc: true, 29 | } 30 | 31 | b := (*[12]byte)(unsafe.Pointer(&d)) 32 | fmt.Printf("Bytes are %#v\n", b) 33 | */ 34 | } 35 | -------------------------------------------------------------------------------- /lessons/structs/struct_alignment_2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | type data1 struct { 9 | aaa bool 10 | bbb [1023]byte 11 | ccc bool 12 | } 13 | 14 | func main() { 15 | d := data1{} 16 | fmt.Println(unsafe.Sizeof(d)) 17 | fmt.Println(unsafe.Alignof(d)) 18 | } 19 | -------------------------------------------------------------------------------- /lessons/structs/struct_inside_function/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func HandleRequest() { 4 | type request struct { 5 | name string 6 | surname string 7 | balance float32 8 | } 9 | 10 | var req request 11 | _ = req 12 | } 13 | -------------------------------------------------------------------------------- /lessons/structs/stuct_sugar/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Data struct { 4 | } 5 | 6 | func (d Data) Print() {} 7 | 8 | func main() { 9 | var value1 = Data{} 10 | value1.Print() 11 | 12 | // 1 way 13 | var value2WithSugar = &Data{} 14 | value2WithSugar.Print() 15 | 16 | // 2 way 17 | var value2WithoutSugar = new(Data) 18 | (*value2WithoutSugar).Print() 19 | } 20 | -------------------------------------------------------------------------------- /lessons/structs/type_alias_and_definition/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type ( 4 | A = int 5 | B int 6 | ) 7 | 8 | func main() { 9 | var a A = 1 10 | var b B = 2 11 | 12 | var ia int = a 13 | _ = ia 14 | 15 | var ib int = int(b) 16 | _ = ib 17 | } 18 | -------------------------------------------------------------------------------- /lessons/structs/type_alias_and_definition_with_method/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Data struct { 6 | } 7 | 8 | func (d Data) Print() { 9 | fmt.Println("data") 10 | } 11 | 12 | type ( 13 | DataType Data 14 | DataAlias = Data 15 | ) 16 | 17 | func main() { 18 | data1 := DataType{} 19 | data1.Print() // compilation error 20 | 21 | data2 := DataAlias{} 22 | data2.Print() 23 | } 24 | -------------------------------------------------------------------------------- /lessons/structs/type_embedding_correct/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "io" 4 | 5 | type LoggerV1 struct { 6 | closer io.WriteCloser 7 | } 8 | 9 | func (l *LoggerV1) Write(data []byte) (int, error) { 10 | return l.closer.Write(data) 11 | } 12 | 13 | func (l *LoggerV1) Close() error { 14 | return l.closer.Close() 15 | } 16 | 17 | type LoggerV2 struct { 18 | io.WriteCloser 19 | } 20 | 21 | func main() { 22 | v1 := LoggerV1{} 23 | v1.Write(nil) 24 | v1.Close() 25 | 26 | v2 := LoggerV2{} 27 | v2.Write(nil) 28 | v2.Close() 29 | } 30 | -------------------------------------------------------------------------------- /lessons/structs/type_embedding_incorrect/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | type Storage struct { 6 | sync.Mutex 7 | data map[string]string 8 | } 9 | 10 | func NewStorage() *Storage { 11 | return &Storage{ 12 | data: make(map[string]string), 13 | } 14 | } 15 | 16 | func (s *Storage) Get(key string) (string, bool) { 17 | s.Lock() 18 | defer s.Unlock() 19 | 20 | value, found := s.data[key] 21 | return value, found 22 | } 23 | 24 | func main() { 25 | storage := NewStorage() 26 | storage.Get("key_1") 27 | 28 | storage.Lock() // dangerous 29 | storage.Unlock() // dangerous 30 | } 31 | -------------------------------------------------------------------------------- /lessons/structs/union_1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "unsafe" 4 | 5 | // SBO (Small Buffer Optimization) 6 | type SBO struct { 7 | size int64 8 | union [16]byte // 8B[pointer]8B[capacity] 9 | } 10 | 11 | func main() { 12 | var small SBO 13 | small.size = 10 14 | small.union = [16]byte{} 15 | 16 | var big SBO 17 | big.size = 1024 18 | pointer := (*[2048]byte)(unsafe.Pointer(&big.union)) 19 | *pointer = [2048]byte{} 20 | capacity := (*int64)(unsafe.Add(unsafe.Pointer(&big.union), 8)) 21 | *capacity = 2048 22 | } 23 | -------------------------------------------------------------------------------- /lessons/structs/union_2/main.go: -------------------------------------------------------------------------------- 1 | package main -------------------------------------------------------------------------------- /lessons/structs/unsafe_cast/performance_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | "unsafe" 6 | ) 7 | 8 | // go test -bench=. -benchmem performance_test.go 9 | 10 | type Int int 11 | 12 | var convertedData []int 13 | 14 | func BenchmarkCast(b *testing.B) { 15 | data := make([]Int, 1024) 16 | for i := 0; i < b.N; i++ { 17 | convertedData = make([]int, 1024) 18 | for idx, value := range data { 19 | convertedData[idx] = int(value) 20 | } 21 | } 22 | } 23 | 24 | func BenchmarkUnsafeCast(b *testing.B) { 25 | data := make([]Int, 1024) 26 | for i := 0; i < b.N; i++ { 27 | convertedData = *(*[]int)(unsafe.Pointer(&data)) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lessons/sync_primitives/action_during_actions/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync/atomic" 4 | 5 | // Need to show solution 6 | 7 | type Data struct { 8 | count atomic.Int32 9 | } 10 | 11 | func (d *Data) Process() { 12 | d.count.Add(1) 13 | if d.count.CompareAndSwap(100, 0) { 14 | // do something... 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lessons/sync_primitives/atomic_performance/perf_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | "testing" 7 | ) 8 | 9 | // go test -bench=. perf_test.go 10 | 11 | func BenchmarkMutexAdd(b *testing.B) { 12 | var number int32 13 | var mutex sync.Mutex 14 | for i := 0; i < b.N; i++ { 15 | mutex.Lock() 16 | number++ 17 | mutex.Unlock() 18 | } 19 | } 20 | 21 | func BenchmarkAtomicAdd(b *testing.B) { 22 | var number atomic.Int32 23 | for i := 0; i < b.N; i++ { 24 | number.Add(1) 25 | } 26 | } 27 | 28 | func BenchmarkAdd(b *testing.B) { 29 | var number int32 30 | for i := 0; i < b.N; i++ { 31 | number++ 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lessons/sync_primitives/cas_loop/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync/atomic" 5 | ) 6 | 7 | func IncrementAndGet(pointer *int32) int32 { 8 | for { 9 | currentValue := atomic.LoadInt32(pointer) 10 | nextValue := currentValue + 1 11 | if atomic.CompareAndSwapInt32(pointer, currentValue, nextValue) { 12 | return nextValue 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lessons/sync_primitives/compare_and_swap/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "sync/atomic" 7 | ) 8 | 9 | // Need to show solution 10 | 11 | var data map[string]string 12 | var initialized atomic.Bool 13 | 14 | func initialize() { 15 | if !initialized.Load() { 16 | initialized.Store(true) 17 | data = make(map[string]string) 18 | fmt.Println("initialized") 19 | } 20 | } 21 | 22 | func main() { 23 | wg := sync.WaitGroup{} 24 | wg.Add(1000) 25 | 26 | for i := 0; i < 1000; i++ { 27 | go func() { 28 | defer wg.Done() 29 | initialize() 30 | }() 31 | } 32 | 33 | wg.Wait() 34 | } 35 | -------------------------------------------------------------------------------- /lessons/sync_primitives/cond_operations/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | func waitWithoutLock() { 6 | cond := sync.NewCond(&sync.Mutex{}) 7 | cond.Wait() 8 | } 9 | 10 | func waitAfterSignal() { 11 | cond := sync.NewCond(&sync.Mutex{}) 12 | cond.Signal() 13 | 14 | cond.L.Lock() 15 | cond.Wait() 16 | cond.L.Unlock() 17 | } 18 | 19 | func main() { 20 | } 21 | -------------------------------------------------------------------------------- /lessons/sync_primitives/correct_increment/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func main() { 9 | mutex := sync.Mutex{} 10 | wg := sync.WaitGroup{} 11 | wg.Add(1000) 12 | 13 | value := 0 14 | for i := 0; i < 1000; i++ { 15 | go func() { 16 | defer wg.Done() 17 | 18 | mutex.Lock() 19 | value++ 20 | mutex.Unlock() 21 | }() 22 | } 23 | 24 | wg.Wait() 25 | 26 | fmt.Println(value) 27 | } 28 | -------------------------------------------------------------------------------- /lessons/sync_primitives/data_race/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func main() { 9 | text := "" 10 | 11 | wg := sync.WaitGroup{} 12 | wg.Add(2) 13 | 14 | go func() { 15 | defer wg.Done() 16 | text = "hello world" 17 | }() 18 | 19 | go func() { 20 | defer wg.Done() 21 | fmt.Println(text) 22 | }() 23 | 24 | wg.Wait() 25 | } 26 | -------------------------------------------------------------------------------- /lessons/sync_primitives/defer_with_mutex/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | // Need to show solution 6 | 7 | var mutex sync.Mutex 8 | 9 | func operation() {} 10 | 11 | func doSomething() { 12 | mutex.Lock() 13 | operation() 14 | mutex.Unlock() 15 | 16 | // some long operation 17 | 18 | mutex.Lock() 19 | operation() 20 | mutex.Unlock() 21 | } 22 | -------------------------------------------------------------------------------- /lessons/sync_primitives/defer_with_panic/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "sync" 6 | ) 7 | 8 | var mutex sync.Mutex 9 | 10 | func functionWithPanic() { 11 | panic("error") 12 | } 13 | 14 | func handle1() { 15 | defer func() { 16 | if err := recover(); err != nil { 17 | log.Println("recovered") 18 | } 19 | }() 20 | 21 | mutex.Lock() 22 | defer mutex.Unlock() 23 | 24 | functionWithPanic() 25 | } 26 | 27 | func handle2() { 28 | defer func() { 29 | if err := recover(); err != nil { 30 | log.Println("recovered") 31 | } 32 | }() 33 | 34 | mutex.Lock() 35 | functionWithPanic() 36 | mutex.Unlock() 37 | } 38 | 39 | func main() { 40 | handle1() 41 | handle2() 42 | } 43 | -------------------------------------------------------------------------------- /lessons/sync_primitives/incorrect_buffer_design/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | type Buffer struct { 6 | mtx sync.Mutex 7 | data []int 8 | } 9 | 10 | func NewBuffer() *Buffer { 11 | return &Buffer{} 12 | } 13 | 14 | func (b *Buffer) Add(value int) { 15 | b.mtx.Lock() 16 | defer b.mtx.Unlock() 17 | 18 | b.data = append(b.data, value) 19 | } 20 | 21 | func (b *Buffer) Data() []int { 22 | b.mtx.Lock() 23 | defer b.mtx.Unlock() 24 | 25 | return b.data 26 | } 27 | -------------------------------------------------------------------------------- /lessons/sync_primitives/incorrect_increment/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func main() { 9 | wg := sync.WaitGroup{} 10 | wg.Add(1000) 11 | 12 | value := 0 13 | for i := 0; i < 1000; i++ { 14 | go func() { 15 | defer wg.Done() 16 | value++ 17 | }() 18 | } 19 | 20 | wg.Wait() 21 | 22 | fmt.Println(value) 23 | } 24 | -------------------------------------------------------------------------------- /lessons/sync_primitives/incorrect_struct_design/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | type Data struct { 6 | sync.Mutex 7 | values []int 8 | } 9 | 10 | func (d *Data) Add(value int) { 11 | d.Lock() 12 | defer d.Unlock() 13 | 14 | d.values = append(d.values, value) 15 | } 16 | 17 | func main() { 18 | data := Data{} 19 | data.Add(100) 20 | 21 | data.Unlock() // Possible problem! 22 | } 23 | -------------------------------------------------------------------------------- /lessons/sync_primitives/local_mutex/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | // Need to show solution 9 | 10 | var value int 11 | 12 | func inc() { 13 | mutex := sync.Mutex{} 14 | 15 | mutex.Lock() 16 | value++ 17 | mutex.Unlock() 18 | } 19 | 20 | func main() { 21 | wg := sync.WaitGroup{} 22 | wg.Add(1000) 23 | 24 | for i := 0; i < 1000; i++ { 25 | go func() { 26 | defer wg.Done() 27 | inc() 28 | }() 29 | } 30 | 31 | wg.Wait() 32 | 33 | fmt.Println(value) 34 | } 35 | -------------------------------------------------------------------------------- /lessons/sync_primitives/lock_granularity/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var mutex sync.Mutex 9 | var cache map[string]string 10 | 11 | func doSomething() { 12 | mutex.Lock() 13 | item := cache["key"] 14 | fmt.Println(item) 15 | mutex.Unlock() 16 | } 17 | -------------------------------------------------------------------------------- /lessons/sync_primitives/lockable_struct/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | type Lockable[T any] struct { 6 | sync.Mutex 7 | Data T 8 | } 9 | 10 | func main() { 11 | var l1 Lockable[int32] 12 | l1.Lock() 13 | l1.Data = 100 14 | l1.Unlock() 15 | 16 | var l2 Lockable[string] 17 | l2.Lock() 18 | l2.Data = "test" 19 | l2.Unlock() 20 | } 21 | -------------------------------------------------------------------------------- /lessons/sync_primitives/mutex_different_operations/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var mutex sync.Mutex 9 | var value string 10 | 11 | func set(v string) { 12 | mutex.Lock() 13 | value = v 14 | mutex.Unlock() 15 | } 16 | 17 | func print() { 18 | mutex.Lock() 19 | fmt.Println(value) 20 | mutex.Unlock() 21 | } 22 | -------------------------------------------------------------------------------- /lessons/sync_primitives/mutex_operations/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | func lockAnyTimes() { 6 | mutex := sync.Mutex{} 7 | mutex.Lock() 8 | mutex.Lock() 9 | } 10 | 11 | func unlockWithoutLock() { 12 | mutex := sync.Mutex{} 13 | mutex.Unlock() 14 | } 15 | 16 | func unlockFromAnotherGoroutine() { 17 | mutex := sync.Mutex{} 18 | mutex.Lock() 19 | 20 | wg := sync.WaitGroup{} 21 | wg.Add(1) 22 | 23 | go func() { 24 | defer wg.Done() 25 | mutex.Unlock() 26 | }() 27 | 28 | wg.Wait() 29 | 30 | mutex.Lock() 31 | mutex.Unlock() 32 | } 33 | 34 | func main() { 35 | } 36 | -------------------------------------------------------------------------------- /lessons/sync_primitives/mutex_with_common_values/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | // go run -race main.go 6 | 7 | type Data struct { 8 | X int 9 | Y int 10 | } 11 | 12 | func main() { 13 | var data Data 14 | values := make([]int, 2) 15 | 16 | wg := sync.WaitGroup{} 17 | wg.Add(2) 18 | 19 | go func() { 20 | defer wg.Done() 21 | 22 | data.X = 5 23 | values[0] = 5 24 | }() 25 | 26 | go func() { 27 | defer wg.Done() 28 | 29 | data.Y = 10 30 | values[1] = 10 31 | }() 32 | 33 | wg.Wait() 34 | } 35 | -------------------------------------------------------------------------------- /lessons/sync_primitives/mutex_with_local_values/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "sync" 6 | ) 7 | 8 | // Need to show solution 9 | 10 | func main() { 11 | mutex := sync.Mutex{} 12 | wg := sync.WaitGroup{} 13 | wg.Add(1000) 14 | 15 | for i := 0; i < 10; i++ { 16 | go func() { 17 | defer wg.Done() 18 | 19 | value := 0 20 | for j := 0; j < 10; j++ { 21 | mutex.Lock() 22 | value++ 23 | mutex.Unlock() 24 | } 25 | 26 | log.Println(value) 27 | }() 28 | } 29 | 30 | wg.Wait() 31 | } 32 | -------------------------------------------------------------------------------- /lessons/sync_primitives/rlocker/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | func withLock(mutex sync.Locker, action func()) { 6 | if action == nil { 7 | return 8 | } 9 | 10 | mutex.Lock() 11 | defer mutex.Unlock() 12 | 13 | action() 14 | } 15 | 16 | func main() { 17 | mutex := sync.RWMutex{} 18 | withLock(&mutex, func() { 19 | // write lock 20 | }) 21 | 22 | withLock(mutex.RLocker(), func() { 23 | // read lock 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /lessons/sync_primitives/rw_mutex_operations/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | func RUnlockLockedMutex() { 6 | m := sync.RWMutex{} 7 | m.Lock() 8 | m.RUnlock() 9 | } 10 | 11 | func UnlockRLockedMutex() { 12 | m := sync.RWMutex{} 13 | m.RLock() 14 | m.Unlock() 15 | } 16 | 17 | func LockRLockedMutex() { 18 | m := sync.RWMutex{} 19 | m.Lock() 20 | m.RLock() 21 | } 22 | 23 | func main() { 24 | } 25 | -------------------------------------------------------------------------------- /lessons/sync_primitives/rw_mutex_performance/perf_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | // go test -bench=. perf_test.go 9 | 10 | func BenchmarkMutexAdd(b *testing.B) { 11 | var number int32 12 | var mutex sync.Mutex 13 | for i := 0; i < b.N; i++ { 14 | mutex.Lock() 15 | number++ 16 | mutex.Unlock() 17 | } 18 | } 19 | 20 | func BenchmarkRWMutexAdd(b *testing.B) { 21 | var number int32 22 | var mutex sync.RWMutex 23 | for i := 0; i < b.N; i++ { 24 | mutex.Lock() 25 | number++ 26 | mutex.Unlock() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lessons/sync_primitives/rw_mutex_with_map/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | type Counters struct { 6 | mu sync.RWMutex 7 | m map[string]int 8 | } 9 | 10 | func (c *Counters) Load(key string) (int, bool) { 11 | c.mu.RLock() 12 | defer c.mu.RUnlock() 13 | 14 | value, found := c.m[key] 15 | return value, found 16 | } 17 | 18 | func (c *Counters) Store(key string, value int) { 19 | c.mu.Lock() 20 | defer c.mu.Unlock() 21 | 22 | c.m[key] = value 23 | } 24 | -------------------------------------------------------------------------------- /lessons/sync_primitives/semaphore/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type Semaphore struct { 8 | count int 9 | max int 10 | condition *sync.Cond 11 | } 12 | 13 | func NewSemaphore(limit int) *Semaphore { 14 | mutex := &sync.Mutex{} 15 | return &Semaphore{ 16 | max: limit, 17 | condition: sync.NewCond(mutex), 18 | } 19 | } 20 | 21 | func (s *Semaphore) Acquire() { 22 | s.condition.L.Lock() 23 | defer s.condition.L.Unlock() 24 | 25 | for s.count >= s.max { 26 | s.condition.Wait() 27 | } 28 | 29 | s.count++ 30 | } 31 | 32 | func (s *Semaphore) Release() { 33 | s.condition.L.Lock() 34 | defer s.condition.L.Unlock() 35 | 36 | s.count-- 37 | s.condition.Signal() 38 | } 39 | -------------------------------------------------------------------------------- /lessons/sync_primitives/wait_group_copying/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | func done(wg sync.WaitGroup) { 6 | wg.Done() 7 | } 8 | 9 | func main() { 10 | wg := sync.WaitGroup{} 11 | wg.Add(1) 12 | done(wg) 13 | wg.Wait() 14 | } 15 | -------------------------------------------------------------------------------- /lessons/sync_primitives/wait_group_operations/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | func makeNegativeCounter() { 6 | wg := sync.WaitGroup{} 7 | wg.Add(-10) 8 | } 9 | 10 | func waitZeroCounter() { 11 | wg := sync.WaitGroup{} 12 | wg.Wait() 13 | } 14 | 15 | func main() { 16 | } 17 | -------------------------------------------------------------------------------- /lessons/sync_primitives/waiting_goroutines/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "log" 4 | 5 | // Need to show solution 6 | 7 | func main() { 8 | for i := 0; i < 5; i++ { 9 | go func() { 10 | log.Println("test") 11 | }() 12 | } 13 | } 14 | --------------------------------------------------------------------------------