├── .gitignore ├── LICENSE ├── README.md ├── chapter1 └── sources │ ├── sieve.c │ ├── sieve.go │ └── sieve.hs ├── chapter10 └── sources │ ├── go-generate │ ├── bindata-demo │ │ ├── main.go │ │ ├── static.go │ │ └── static │ │ │ └── img │ │ │ └── go-mascot.jpg │ ├── enum-demo │ │ └── main.go │ ├── generate-args │ │ ├── go.mod │ │ ├── main.go │ │ ├── subpkg1 │ │ │ └── subpkg1.go │ │ └── subpkg2 │ │ │ └── subpkg2.go │ ├── multi_go_generate_directive.go │ ├── protobuf-make │ │ ├── IDL │ │ │ └── msg.proto │ │ ├── Makefile │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ └── msg │ │ │ └── msg.pb.go │ ├── protobuf │ │ ├── IDL │ │ │ └── msg.proto │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ └── msg │ │ │ └── msg.pb.go │ └── stringer-demo │ │ ├── main.go │ │ └── weekday_string.go │ ├── go-module │ └── hello │ │ ├── go.mod │ │ ├── go.sum │ │ ├── hello │ │ ├── hello.go │ │ └── vendor │ │ ├── bitbucket.org │ │ └── bigwhite │ │ │ ├── c │ │ │ ├── README.md │ │ │ ├── c.go │ │ │ └── go.mod │ │ │ └── d │ │ │ ├── README.md │ │ │ └── d.go │ │ └── modules.txt │ ├── go-tools │ ├── build_with_race_option.go │ ├── gctrace.go │ ├── linker_x_flag.go │ ├── preemption_scheduler.go │ ├── refactor │ │ ├── gofmt-demo │ │ │ ├── cmd │ │ │ │ └── demo │ │ │ │ │ └── main.go │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ └── pkg │ │ │ │ ├── bar │ │ │ │ └── bar.go │ │ │ │ └── foo │ │ │ │ └── foo.go │ │ └── src │ │ │ └── github.com │ │ │ └── bigwhite │ │ │ ├── gomvpkg-demo │ │ │ ├── cmd │ │ │ │ └── demo │ │ │ │ │ └── main.go │ │ │ ├── go.mod │ │ │ └── pkg │ │ │ │ └── foo │ │ │ │ └── example.go │ │ │ └── gorename-demo │ │ │ ├── cmd │ │ │ └── demo │ │ │ │ └── main.go │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ └── pkg │ │ │ └── foo │ │ │ └── foo.go │ ├── tags-demo │ │ ├── main.go │ │ ├── pro.go │ │ ├── ultimate.go │ │ └── ultimate_win.go │ ├── vet_assign.go │ ├── vet_atomic.go │ ├── vet_bools.go │ ├── vet_buildtag.go │ ├── vet_composites.go │ ├── vet_copylocks.go │ ├── vet_loopclosure.go │ ├── vet_printf.go │ ├── vet_unmarshal.go │ └── vet_unsafeptr.go │ ├── go-trap │ ├── break_1.go │ ├── break_2.go │ ├── channel_1.go │ ├── for_range_1.go │ ├── for_range_2.go │ ├── for_range_3.go │ ├── for_range_4.go │ ├── for_range_5.go │ ├── goroutine_1.go │ ├── goroutine_2.go │ ├── goroutine_3.go │ ├── goroutine_4.go │ ├── goroutine_5.go │ ├── http_1.go │ ├── http_2.go │ ├── http_3.go │ ├── json_1.go │ ├── json_2.go │ ├── json_3.go │ ├── json_4.go │ ├── method_1.go │ ├── method_2.go │ ├── multi_variable_short_declaration.go │ ├── nil_interface_1.go │ ├── nil_interface_2.go │ ├── nil_type_1.go │ ├── nil_type_2.go │ ├── short_declaration_variable_shadowing_1.go │ ├── short_declaration_variable_shadowing_2.go │ ├── short_declaration_variable_shadowing_3.go │ ├── slice_1.go │ ├── slice_2.go │ ├── slice_3.go │ ├── slice_4.go │ ├── slice_5.go │ ├── string_1.go │ ├── switch.c │ ├── switch_1.go │ └── time_1.go │ └── tiny-image │ ├── Dockerfile │ ├── Dockerfile.build │ ├── Dockerfile.build.alpine │ ├── Dockerfile.multistage │ ├── Dockerfile.target │ ├── Dockerfile.target.alpine │ └── httpserver.go ├── chapter2 └── sources │ ├── GoLibProj │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── go.mod │ ├── internal │ │ ├── ilib1 │ │ │ └── ilib1.go │ │ └── ilib2 │ │ │ └── ilib2.go │ ├── lib.go │ ├── lib1 │ │ └── lib1.go │ └── lib2 │ │ └── lib2.go │ ├── GoProj │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── cmd │ │ ├── app1 │ │ │ └── main.go │ │ └── app2 │ │ │ └── main.go │ ├── go.mod │ └── pkg │ │ ├── lib1 │ │ └── lib1.go │ │ └── lib2 │ │ └── lib2.go │ └── gofmt_demo.go ├── chapter3 └── sources │ ├── bytes_buffer_write.go │ ├── call_method_through_nil_pointer.go │ ├── control_structure_idiom_1.go │ ├── control_structure_idiom_2.go │ ├── control_structure_idiom_3.go │ ├── control_structure_idiom_4.go │ ├── control_structure_idiom_5.go │ ├── control_structure_idiom_6.go │ ├── control_structure_idiom_7.go │ ├── evaluation_order_1.go │ ├── evaluation_order_2.go │ ├── evaluation_order_3.go │ ├── evaluation_order_4.go │ ├── evaluation_order_5.go │ ├── evaluation_order_6.go │ ├── evaluation_order_7.go │ ├── evaluation_order_8.go │ ├── for_range_bench_test.go │ ├── item16-demo │ ├── chapter3-demo1 │ │ ├── cmd │ │ │ ├── app1 │ │ │ │ └── main.go │ │ │ ├── app2 │ │ │ │ └── main.go │ │ │ └── app3 │ │ │ │ ├── app3 │ │ │ │ └── main.go │ │ ├── go.mod │ │ └── pkg │ │ │ ├── pkg1 │ │ │ └── pkg1.go │ │ │ └── pkg2 │ │ │ └── pkg2.go │ └── chapter3-demo2 │ │ └── pkg │ │ └── pkg1 │ │ └── pkg1.go │ ├── map_concurrent_read_and_write.go │ ├── map_iterate.go │ ├── map_multiple_iterate.go │ ├── map_stable_iterate.go │ ├── map_test.go │ ├── map_var_as_param.go │ ├── slice_append.go │ ├── slice_benchmark_test.go │ ├── slice_unbind_orig_array.go │ ├── string_as_param_benchmark_test.go │ ├── string_compare.go │ ├── string_concat_benchmark_test.go │ ├── string_for_range_covert_optimize.go │ ├── string_immutable1.go │ ├── string_immutable2.go │ ├── string_immutable3.go │ ├── string_mallocs_in_convert.go │ ├── string_multilines.go │ ├── string_nonascii.go │ ├── string_slice_to_string.go │ ├── string_type.go │ └── varinit.c ├── chapter4 └── sources │ ├── .gitkeeper │ ├── call_init_in_main.go │ ├── defer_perf_benchmark_1_test.go │ ├── deferred_func_1.go │ ├── deferred_func_2.go │ ├── deferred_func_3.go │ ├── deferred_func_4.go │ ├── deferred_func_5.go │ ├── deferred_func_6.go │ ├── deferred_func_7.go │ ├── deferred_func_8.go │ ├── function_as_first_class_citizen_1.go │ ├── function_as_first_class_citizen_2.go │ ├── function_as_first_class_citizen_3.go │ ├── function_as_first_class_citizen_4.go │ ├── function_as_first_class_citizen_5.go │ ├── function_as_first_class_citizen_6.go │ ├── function_as_first_class_citizen_7.go │ ├── function_as_first_class_citizen_8.go │ ├── function_as_first_class_citizen_9.go │ ├── get_image_size.go │ ├── method_nature_1.go │ ├── method_nature_2.go │ ├── method_nature_3.go │ ├── method_nature_4.go │ ├── method_nature_5.go │ ├── method_nature_6.go │ ├── method_set_1.go │ ├── method_set_10.go │ ├── method_set_11.go │ ├── method_set_12.go │ ├── method_set_2.go │ ├── method_set_3.go │ ├── method_set_4.go │ ├── method_set_5.go │ ├── method_set_6.go │ ├── method_set_7.go │ ├── method_set_8.go │ ├── method_set_9.go │ ├── method_set_9_test.go │ ├── method_set_utils.go │ ├── package-init-order │ ├── go.mod │ ├── main.go │ ├── pkg1 │ │ └── pkg1.go │ ├── pkg2 │ │ └── pkg2.go │ └── pkg3 │ │ └── pkg3.go │ ├── variadic_function_1.go │ ├── variadic_function_2.go │ ├── variadic_function_3.go │ ├── variadic_function_4.go │ ├── variadic_function_5.go │ ├── variadic_function_6.go │ ├── variadic_function_7.go │ ├── variadic_function_8.go │ └── variadic_function_9.go ├── chapter5 └── sources │ ├── dumpinterface.go │ ├── horizontal-composition-1.go │ ├── horizontal-composition-2.go │ ├── horizontal-composition-3.go │ ├── horizontal-composition-4.go │ ├── interface-internal-1.go │ ├── interface-internal-2.go │ ├── interface-internal-3.go │ ├── interface-internal-4.go │ ├── interface-internal-4.o │ ├── interface-internal-4.s │ ├── interface-internal-5.go │ ├── java_stringer │ ├── Makefile │ ├── README.md │ ├── StringerInterface.java │ ├── bar.java │ ├── foo.java │ └── stringer │ │ ├── Stringer.class │ │ ├── StringerInterface.class │ │ ├── bar.class │ │ └── foo.class │ ├── ruby_stringer │ └── stringer_interface.rb │ └── send_mail_with_disclaimer │ ├── v1 │ ├── go.mod │ ├── go.sum │ ├── mail.go │ └── mail_test.go │ └── v2 │ ├── example_test.go │ ├── go.mod │ ├── go.sum │ ├── mail.go │ └── mail_test.go ├── chapter6 └── sources │ ├── concurrency-design-airport-securitycheck-1.go │ ├── concurrency-design-airport-securitycheck-2.go │ ├── concurrency-design-airport-securitycheck-3.go │ ├── go-atomic-package-1_test.go │ ├── go-atomic-package-2_test.go │ ├── go-channel-case-1.go │ ├── go-channel-case-10.go │ ├── go-channel-case-2.go │ ├── go-channel-case-3.go │ ├── go-channel-case-4.go │ ├── go-channel-case-5.go │ ├── go-channel-case-6.go │ ├── go-channel-case-7.go │ ├── go-channel-case-8.go │ ├── go-channel-case-9.go │ ├── go-channel-operation-benchmark │ ├── buffered-chan │ │ ├── multi_to_multi_cap_100_test.go │ │ ├── multi_to_multi_cap_10_test.go │ │ ├── one_to_one_cap_100_test.go │ │ └── one_to_one_cap_10_test.go │ └── unbuffered-chan │ │ ├── multi_to_multi_test.go │ │ └── one_to_one_test.go │ ├── go-concurrency-pattern-1.go │ ├── go-concurrency-pattern-10.go │ ├── go-concurrency-pattern-11.go │ ├── go-concurrency-pattern-12.go │ ├── go-concurrency-pattern-2.go │ ├── go-concurrency-pattern-3.go │ ├── go-concurrency-pattern-4.go │ ├── go-concurrency-pattern-5.go │ ├── go-concurrency-pattern-6.go │ ├── go-concurrency-pattern-7.go │ ├── go-concurrency-pattern-7_test.go │ ├── go-concurrency-pattern-8.go │ ├── go-concurrency-pattern-9.go │ ├── go-scheduler-model-case1.go │ ├── go-scheduler-model-case2.go │ ├── go-scheduler-model-case3.go │ ├── go-scheduler-model-case4.go │ ├── go-sync-package-1_test.go │ ├── go-sync-package-2.go │ ├── go-sync-package-3_test.go │ ├── go-sync-package-4.go │ ├── go-sync-package-5.go │ ├── go-sync-package-6.go │ └── go-sync-package-7_test.go ├── chapter7 └── sources │ ├── JavaDemoHeightException │ ├── Demo.java │ ├── HeightInput.java │ ├── HeightOutOfBound.java │ ├── Makefile │ ├── README.md │ └── demo │ │ └── .gitkeeper │ ├── go-error-handling-strategy-1.go │ ├── go-error-handling-strategy-2.go │ ├── go-if-error-check-optimize-1.go │ ├── go-if-error-check-optimize-2.go │ ├── go-if-error-check-optimize-3.go │ ├── go-panic-stacktrace.go │ └── panic_recover_performance_test.go ├── chapter8 └── sources │ ├── benchmark-compare │ ├── new.txt │ ├── new_with_mem.txt │ ├── old.txt │ ├── old_with_mem.txt │ └── strcat_test.go │ ├── benchmark-impl │ ├── paralell_test.go │ └── sequential_test.go │ ├── benchmark_intro_test.go │ ├── benchmark_paralell_demo_test.go │ ├── benchmark_with_expensive_context_setup_test.go │ ├── classic_package_level_testfixture_test.go │ ├── classic_testfixture_test.go │ ├── delve-demo1 │ ├── cmd │ │ └── delve-demo1 │ │ │ └── main.go │ ├── go.mod │ └── pkg │ │ └── foo │ │ └── foo.go │ ├── delve-demo2 │ ├── .swp │ ├── cmd │ │ └── delve-demo2 │ │ │ └── main.go │ ├── go.mod │ └── pkg │ │ ├── bar │ │ └── bar.go │ │ └── foo │ │ └── foo.go │ ├── delve-demo3 │ └── main.go │ ├── expvar_demo1.go │ ├── expvar_demo2.go │ ├── expvar_demo3.go │ ├── expvar_demo4.go │ ├── expvar_demo5.go │ ├── expvar_demo6.go │ ├── faketest1 │ ├── go.mod │ ├── mailclient.go │ ├── mailclient_test.go │ ├── mailer │ │ └── mailer.go │ └── sign │ │ └── sign.go │ ├── fuzz-test-demo │ ├── corpus │ │ ├── 1b7c3c5fec431a18fdebaa415d1f89a8f7a325bd-4 │ │ ├── 1c10cdd1846110ecd86a3cb4c28e2c2cf101b284-2 │ │ ├── 2f438287a845a438f2af2e9c27b1864cf0b3e1fa-3 │ │ ├── 48899690e4a8e4c04ff60ea6cdd52ec80a394b69-5 │ │ ├── 66a37c87267bf17ae4c794158f1de4bc70ac8ab2-1 │ │ └── da39a3ee5e6b4b0d3255bfef95601890afd80709 │ ├── crashers │ │ ├── df779ced6b712c5fca247e465de2de474d1d23b9 │ │ ├── df779ced6b712c5fca247e465de2de474d1d23b9.output │ │ └── df779ced6b712c5fca247e465de2de474d1d23b9.quoted │ ├── go.mod │ ├── go.sum │ ├── parse_complex.go │ ├── parse_complex_fuzz.go │ └── suppressions │ │ └── 4db970443bac2de13454771685ab603e779152b4 │ ├── go-pprof-optimization-demo │ ├── step0 │ │ └── demo.go │ ├── step1 │ │ ├── cpu.prof │ │ ├── demo.go │ │ └── demo_test.go │ ├── step2 │ │ ├── demo.go │ │ ├── demo_test.go │ │ └── mem.prof │ ├── step3 │ │ ├── demo.go │ │ ├── demo_test.go │ │ └── mem.prof │ ├── step4 │ │ ├── demo.go │ │ ├── demo_test.go │ │ └── mem.prof │ └── step5 │ │ ├── block.prof │ │ ├── demo.go │ │ └── demo_test.go │ ├── mocktest │ ├── go.mod │ ├── go.sum │ ├── mailclient.go │ ├── mailclient_test.go │ ├── mailer │ │ ├── mailer.go │ │ └── mock_mailer.go │ └── sign │ │ └── sign.go │ ├── non_table_driven_strings_test.go │ ├── pprof_standalone1.go │ ├── pprof_standalone1_cpu.prof │ ├── pprof_standalone2.go │ ├── pprof_standalone3.go │ ├── pprof_standalone4.go │ ├── strings-test-demo │ ├── builder_test.go │ └── compare_test.go │ ├── stubtest1 │ ├── go.mod │ ├── weather_cli.go │ └── weather_cli_test.go │ ├── stubtest2 │ ├── go.mod │ ├── mailclient.go │ ├── mailclient_test.go │ ├── mailer │ │ └── mailer.go │ └── sign │ │ └── sign.go │ ├── stubtest3 │ ├── go.mod │ ├── go.sum │ ├── mailclient.go │ ├── mailclient_test.go │ ├── mailer │ │ └── mailer.go │ └── sign │ │ └── sign.go │ ├── table_driven_strings_by_name_test.go │ ├── table_driven_strings_by_offset_test.go │ ├── table_driven_strings_more_cases_test.go │ ├── table_driven_strings_test.go │ ├── table_driven_strings_with_map_test.go │ ├── table_driven_strings_with_subtest_test.go │ ├── testdata-demo1 │ ├── attendee.go │ ├── attendee_test.go │ └── testdata │ │ └── attendee1.xml │ ├── testdata-demo2 │ ├── attendee.go │ ├── attendee_test.go │ └── testdata │ │ └── attendee1.golden │ └── xunit_suite_level_testfixture_test.go ├── chapter9 └── sources │ ├── go-bytes-and-strings │ ├── byte_slice_equality.go │ ├── byte_slice_test_equality_with_operator.go │ ├── bytes_compare.go │ ├── equalfold.go │ ├── join_and_builder.go │ ├── search_and_replace.go │ ├── split_and_fields.go │ ├── string_and_bytes_reader.go │ └── trim_and_transform.go │ ├── go-cgo │ ├── c_array_to_go_slice.go │ ├── c_char_array_to_go_byte_slice.go │ ├── c_enum.go │ ├── c_errno.go │ ├── c_struct.go │ ├── c_type_size.go │ ├── c_union_1.go │ ├── c_union_2.go │ ├── cgo-perf │ │ ├── cgo_call.go │ │ └── cgo_call_test.go │ ├── cgo_sleep.go │ ├── foo.c │ ├── foo.go │ ├── foo.h │ ├── go_sleep.go │ ├── how_cgo_works.go │ └── server.go │ ├── go-character-set-encoding │ ├── convert_gb18030_to_utf16_and_utf32.go │ ├── convert_utf8_to_gb18030.go │ ├── dump_utf8_encoding_of_string.go │ ├── gb18030.txt │ ├── rune_encode_and_decode.go │ ├── utf16be-no-bom.txt │ ├── utf16be.txt │ └── utf32be-no-bom.txt │ ├── go-crypto │ ├── aes_cbc_cipher_decrypt.go │ ├── aes_cbc_cipher_encrypt.go │ ├── block_cipher_decrypt.pseudocode │ ├── block_cipher_encrypt.pseudocode │ ├── hmac_generate.go │ ├── rand_generate.go │ ├── rsa_key_generate.go │ ├── rsa_oaep_encrypt_and_decrypt.go │ ├── rsa_pss_sign_and_verify.go │ └── sha256_sum.go │ ├── go-https │ ├── ca.crt │ ├── ca.key │ ├── ca.srl │ ├── client.crt │ ├── client.csr │ ├── client.key │ ├── hello.signed │ ├── hello.txt │ ├── hello.verify │ ├── hello_world_server.go │ ├── https_hello_world_server.go │ ├── server-signed-by-ca.crt │ ├── server.crt │ ├── server.csr │ ├── server.key │ ├── verify-dual-cert │ │ ├── client_provide_cert.go │ │ ├── client_verify_by_cacert.go │ │ └── hello_world_server.go │ └── verify-server-cert │ │ ├── client_skip_verify.go │ │ ├── client_verify_by_cacert.go │ │ ├── client_without_cacert.go │ │ └── hello_world_server.go │ ├── go-read-and-write │ ├── .bufio_write_byte_slice.go.swp │ ├── bufio.txt │ ├── bufio_read_byte_slice.go │ ├── bufio_write_byte_slice.go │ ├── direct_read_and_write_adt_in_binary.go │ ├── direct_read_and_write_adt_in_fmt.go │ ├── direct_read_and_write_adt_in_gob.go │ ├── direct_read_and_write_byte_slice.go │ ├── direct_read_byte_slice_meets_eof.go │ ├── gzip_compress_data.go │ └── gzip_decompress_data.go │ ├── go-reflect │ ├── call_func_and_method.go │ ├── construct_sql_query_stmt.go │ ├── examine_value_and_type.go │ ├── reflect_value_settable.go │ └── reflect_value_to_interface.go │ ├── go-signal │ ├── go-program-exit-gracefully-with-notify.go │ ├── go-program-notify-lost-signal.go │ ├── go-program-notify-signal-twice-on-same-channel.go │ ├── go-program-notify-signal-twice.go │ ├── go-program-notify-sync-and-async-signal.go │ └── go-program-without-signal-handling.go │ ├── go-tcpsock │ ├── conn_close │ │ ├── client1.go │ │ └── server1.go │ ├── conn_establish │ │ ├── client1.go │ │ ├── client2.go │ │ ├── client3.go │ │ └── server2.go │ ├── read_write │ │ ├── client1.go │ │ ├── client2.go │ │ ├── client3.go │ │ ├── client4.go │ │ ├── client5.go │ │ ├── client6.go │ │ ├── server1.go │ │ ├── server2.go │ │ ├── server3.go │ │ ├── server4.go │ │ └── server5.go │ └── server.go │ ├── go-time-operations │ ├── compare_two_time_with_equal.go │ ├── compare_two_time_with_operator.go │ ├── construct_time_with_func_date.go │ ├── construct_time_with_func_now.go │ ├── convert_time_between_tz.go │ ├── diff_two_time_with_sub.go │ ├── get_current_time.go │ ├── get_time_with_tz.go │ ├── strftime_in_c.c │ ├── timeformat_cheatsheet.go │ ├── timeformat_in_c_way.go │ ├── timeformat_in_go_way.go │ ├── timer_create.go │ ├── timer_reset_1.go │ ├── timer_reset_2.go │ ├── timer_reset_3.go │ └── timer_stop.go │ └── go-unsafe │ ├── c_is_not_type_safe.c │ ├── funcs_in_unsafe.go │ ├── go_is_not_type_safe.go │ ├── go_is_type_safe.go │ ├── go_math_float64bits_vs_explicit_type_convertion.go │ ├── go_mem_align_under_pattern_1.go │ ├── go_mem_obj_ref_unsafepointer_vs_uintptr.go │ ├── go_pointer_arithmetic_under_pattern_3.go │ ├── go_slice_and_string_header.go │ ├── go_slice_and_string_header_wrong_case.go │ ├── go_slice_and_string_header_wrong_case_crash.go │ ├── go_stack_obj_ref_by_uintptr.go │ ├── go_struct_assignment_test.go │ └── go_unsafe_compiler_checkptr.go ├── cover.png └── errata.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | .DS_Store 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | *.swp 15 | *.swo 16 | *.swa 17 | 18 | # Dependency directories (remove the comment below to include it) 19 | # vendor/ 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GoProgrammingFromBeginnerToMaster 2 | [《Go语言精进之路》1、2册书籍](https://item.jd.com/13694000.html)配套源代码。 3 | 4 | 本套书的勘误表可在[这里](https://github.com/bigwhite/GoProgrammingFromBeginnerToMaster/blob/main/errata.md)查看。 5 | 6 | 购买套装书请点击[这里](https://item.jd.com/13694000.html)。 7 | 8 | ![](https://github.com/bigwhite/GoProgrammingFromBeginnerToMaster/blob/main/cover.png) 9 | 10 | 11 | -------------------------------------------------------------------------------- /chapter1/sources/sieve.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define LIMIT 50 4 | #define PRIMES 10 5 | 6 | void sieve() { 7 | int c, i,j,numbers[LIMIT], primes[PRIMES]; 8 | 9 | for (i=0;i not $ a `mod` x == 0) xs) 3 | 4 | n = 100 5 | main = print $ sieve [2..n] 6 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/bindata-demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | //go:generate go-bindata -o static.go static/img/go-mascot.jpg 9 | 10 | func main() { 11 | data, err := Asset("static/img/go-mascot.jpg") 12 | if err != nil { 13 | fmt.Println("Asset invoke error:", err) 14 | return 15 | } 16 | 17 | http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { 18 | w.Write(data) 19 | }) 20 | 21 | http.ListenAndServe(":8080", nil) 22 | } 23 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/bindata-demo/static/img/go-mascot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter10/sources/go-generate/bindata-demo/static/img/go-mascot.jpg -------------------------------------------------------------------------------- /chapter10/sources/go-generate/enum-demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Weekday int 6 | 7 | const ( 8 | Sunday Weekday = iota 9 | Monday 10 | Tuesday 11 | Wednesday 12 | Thursday 13 | Friday 14 | Saturday 15 | ) 16 | 17 | func (d Weekday) String() string { 18 | switch d { 19 | case Sunday: 20 | return "Sunday" 21 | case Monday: 22 | return "Monday" 23 | case Tuesday: 24 | return "Tuesday" 25 | case Wednesday: 26 | return "Wednesday" 27 | case Thursday: 28 | return "Thursday" 29 | case Friday: 30 | return "Friday" 31 | case Saturday: 32 | return "Saturday" 33 | } 34 | 35 | return "Sunday" //default 0 -> "Sunday" 36 | } 37 | 38 | func main() { 39 | var d Weekday 40 | fmt.Println(d) 41 | fmt.Println(Weekday(1)) 42 | } 43 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/generate-args/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/generate-args-demo 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/generate-args/main.go: -------------------------------------------------------------------------------- 1 | //go:generate pwd 2 | package main 3 | 4 | func main() { 5 | println("hello, go generate") 6 | } 7 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/generate-args/subpkg1/subpkg1.go: -------------------------------------------------------------------------------- 1 | //go:generate pwd 2 | package subpkg1 3 | 4 | func F() { 5 | } 6 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/generate-args/subpkg2/subpkg2.go: -------------------------------------------------------------------------------- 1 | //go:generate pwd 2 | package subpkg2 3 | 4 | func F() { 5 | } 6 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/multi_go_generate_directive.go: -------------------------------------------------------------------------------- 1 | //go:generate echo "top" 2 | package main 3 | 4 | import "fmt" 5 | 6 | //go:generate echo "middle" 7 | func main() { 8 | fmt.Println("hello, go generate") 9 | } 10 | 11 | //go:generate echo "tail" 12 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/protobuf-make/IDL/msg.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package msg; 4 | 5 | message request { 6 | string msgID = 1; 7 | string field1 = 2; 8 | repeated string field2 = 3; 9 | } 10 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/protobuf-make/Makefile: -------------------------------------------------------------------------------- 1 | all: build 2 | 3 | build: gen-protobuf 4 | go build 5 | 6 | gen-protobuf: 7 | protoc -I ./IDL msg.proto --gofast_out=./msg 8 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/protobuf-make/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/protobuf-demo 2 | 3 | go 1.14 4 | 5 | require github.com/golang/protobuf v1.4.3 6 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/protobuf-make/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | msg "github.com/bigwhite/protobuf-demo/msg" 7 | ) 8 | 9 | //go:generate protoc -I ./IDL msg.proto --gofast_out=./msg 10 | func main() { 11 | var m = msg.Request{ 12 | MsgID: "xxxx", 13 | Field1: "field1", 14 | Field2: []string{"field2-1", "field2-2"}, 15 | } 16 | fmt.Println(m) 17 | } 18 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/protobuf/IDL/msg.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package msg; 4 | 5 | message request { 6 | string msgID = 1; 7 | string field1 = 2; 8 | repeated string field2 = 3; 9 | } 10 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/protobuf/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/protobuf-demo 2 | 3 | go 1.14 4 | 5 | require github.com/golang/protobuf v1.4.3 6 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/protobuf/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | msg "github.com/bigwhite/protobuf-demo/msg" 7 | ) 8 | 9 | //go:generate protoc -I ./IDL msg.proto --gofast_out=./msg 10 | func main() { 11 | var m = msg.Request{ 12 | MsgID: "xxxx", 13 | Field1: "field1", 14 | Field2: []string{"field2-1", "field2-2"}, 15 | } 16 | fmt.Println(m) 17 | } 18 | -------------------------------------------------------------------------------- /chapter10/sources/go-generate/stringer-demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Weekday int 6 | 7 | const ( 8 | Sunday Weekday = iota 9 | Monday 10 | Tuesday 11 | Wednesday 12 | Thursday 13 | Friday 14 | Saturday 15 | ) 16 | 17 | //go:generate stringer -type=Weekday 18 | func main() { 19 | var d Weekday 20 | fmt.Println(d) 21 | fmt.Println(Weekday(1)) 22 | } 23 | -------------------------------------------------------------------------------- /chapter10/sources/go-module/hello/go.mod: -------------------------------------------------------------------------------- 1 | module hello 2 | 3 | go 1.14 4 | 5 | require bitbucket.org/bigwhite/c v1.3.0 6 | -------------------------------------------------------------------------------- /chapter10/sources/go-module/hello/go.sum: -------------------------------------------------------------------------------- 1 | bitbucket.org/bigwhite/c v1.3.0 h1:crNI04Bw6lm1yyRjJ+8lJX+3amsxeU72mVQ41kjnESA= 2 | bitbucket.org/bigwhite/c v1.3.0/go.mod h1:6p3lkm60SJ7QP5a4oJyLUxbDJeT+w5x5CShTrekjc7o= 3 | bitbucket.org/bigwhite/d v1.2.0 h1:QQawlmsVZWwIsr0ockPCSJjN1QoKd4W0KEJrINdIzY0= 4 | bitbucket.org/bigwhite/d v1.2.0/go.mod h1:6XJNbysZ+/91fhY6/3TKkMNdV/c0pgaubTQWMigKnlY= 5 | -------------------------------------------------------------------------------- /chapter10/sources/go-module/hello/hello: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter10/sources/go-module/hello/hello -------------------------------------------------------------------------------- /chapter10/sources/go-module/hello/hello.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "bitbucket.org/bigwhite/c" 4 | 5 | func main() { 6 | c.CallC() 7 | } 8 | -------------------------------------------------------------------------------- /chapter10/sources/go-module/hello/vendor/bitbucket.org/bigwhite/c/README.md: -------------------------------------------------------------------------------- 1 | # README # 2 | 3 | This c repo is used for go module experiment. -------------------------------------------------------------------------------- /chapter10/sources/go-module/hello/vendor/bitbucket.org/bigwhite/c/c.go: -------------------------------------------------------------------------------- 1 | package c 2 | 3 | import ( 4 | "fmt" 5 | 6 | "bitbucket.org/bigwhite/d" 7 | ) 8 | 9 | func CallC() { 10 | fmt.Println("call C: v1.3.0") 11 | fmt.Println(" --> call D:") 12 | fmt.Printf("\t") 13 | d.CallD() 14 | fmt.Println(" --> call D end") 15 | } 16 | -------------------------------------------------------------------------------- /chapter10/sources/go-module/hello/vendor/bitbucket.org/bigwhite/c/go.mod: -------------------------------------------------------------------------------- 1 | module bitbucket.org/bigwhite/c 2 | 3 | require ( 4 | bitbucket.org/bigwhite/d v1.2.0 5 | ) 6 | -------------------------------------------------------------------------------- /chapter10/sources/go-module/hello/vendor/bitbucket.org/bigwhite/d/README.md: -------------------------------------------------------------------------------- 1 | # README # 2 | 3 | This d repo is used for go module experiment. 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /chapter10/sources/go-module/hello/vendor/bitbucket.org/bigwhite/d/d.go: -------------------------------------------------------------------------------- 1 | package d 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func CallD() { 8 | fmt.Println("call D: v1.2.0") 9 | } 10 | -------------------------------------------------------------------------------- /chapter10/sources/go-module/hello/vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # bitbucket.org/bigwhite/c v1.3.0 2 | ## explicit 3 | bitbucket.org/bigwhite/c 4 | # bitbucket.org/bigwhite/d v1.2.0 5 | bitbucket.org/bigwhite/d 6 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/build_with_race_option.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | "sync" 6 | ) 7 | 8 | func main() { 9 | var wg sync.WaitGroup 10 | var m = make(map[int]int, 100) 11 | 12 | for i := 0; i < 100; i++ { 13 | m[i] = i 14 | } 15 | 16 | wg.Add(10) 17 | for i := 0; i < 10; i++ { 18 | // 并发写 19 | go func(i int) { 20 | for n := 0; n < 100; n++ { 21 | n := rand.Intn(100) 22 | m[n] = n 23 | } 24 | wg.Done() 25 | }(i) 26 | } 27 | wg.Wait() 28 | } 29 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/gctrace.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | m := make(map[interface{}]interface{}) 5 | v := "hello, gc" 6 | 7 | for i := 1; i < 1<<31; i++ { 8 | m[i] = v 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/linker_x_flag.go: -------------------------------------------------------------------------------- 1 | // build cmd: go build -ldflags "-X main.version=v0.7.0" linker_x_flag.go 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | var ( 10 | version string 11 | ) 12 | 13 | func main() { 14 | if os.Args[1] == "version" { 15 | fmt.Println("version:", version) 16 | return 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/preemption_scheduler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "time" 7 | ) 8 | 9 | func deadloop() { 10 | for { 11 | } 12 | } 13 | 14 | func main() { 15 | runtime.GOMAXPROCS(1) 16 | go deadloop() 17 | for { 18 | time.Sleep(time.Second * 1) 19 | fmt.Println("I got scheduled!") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/refactor/gofmt-demo/cmd/demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/bigwhite/gofmt-demo/pkg/bar" 7 | "github.com/bigwhite/gofmt-demo/pkg/foo" 8 | ) 9 | 10 | func main() { 11 | foo.Foo() 12 | bar.Bar() 13 | log.Print("gofmt-demo") 14 | } 15 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/refactor/gofmt-demo/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/gofmt-demo 2 | 3 | go 1.14 4 | 5 | require github.com/rs/zerolog v1.20.0 6 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/refactor/gofmt-demo/pkg/bar/bar.go: -------------------------------------------------------------------------------- 1 | package bar 2 | 3 | import "log" 4 | 5 | func Bar() { 6 | log.Print("bar.Bar") 7 | } 8 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/refactor/gofmt-demo/pkg/foo/foo.go: -------------------------------------------------------------------------------- 1 | package foo 2 | 3 | import "log" 4 | 5 | func Foo() { 6 | log.Print("foo.Foo") 7 | } 8 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/refactor/src/github.com/bigwhite/gomvpkg-demo/cmd/demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/bigwhite/gomvpkg-demo/pkg/foo" 5 | ) 6 | 7 | func main() { 8 | foo.DoSomething() 9 | } 10 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/refactor/src/github.com/bigwhite/gomvpkg-demo/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/gomvpkg-demo 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/refactor/src/github.com/bigwhite/gomvpkg-demo/pkg/foo/example.go: -------------------------------------------------------------------------------- 1 | package foo 2 | 3 | import "fmt" 4 | 5 | func DoSomething() { 6 | fmt.Println("do something") 7 | } 8 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/refactor/src/github.com/bigwhite/gorename-demo/cmd/demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/bigwhite/gorename-demo/pkg/foo" 7 | ) 8 | 9 | func main() { 10 | var s = foo.PkgTypeStruct1{ 11 | Field1: "tony", 12 | Age: 20, 13 | } 14 | s.MethodOfPkgType1() 15 | i := foo.NewPkgType1(5) 16 | fmt.Println(*i) 17 | } 18 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/refactor/src/github.com/bigwhite/gorename-demo/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/gorename-demo 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/refactor/src/github.com/bigwhite/gorename-demo/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter10/sources/go-tools/refactor/src/github.com/bigwhite/gorename-demo/go.sum -------------------------------------------------------------------------------- /chapter10/sources/go-tools/refactor/src/github.com/bigwhite/gorename-demo/pkg/foo/foo.go: -------------------------------------------------------------------------------- 1 | package foo 2 | 3 | var PkgVar1 = "pkgVar" 4 | 5 | const PkgConst1 = "pkgConst" 6 | 7 | type PkgType1 int 8 | 9 | type PkgTypeStruct1 struct { 10 | Field1 string 11 | Age int 12 | } 13 | 14 | func (s PkgTypeStruct1) MethodOfPkgType1() { 15 | var localInMethod1 = "MethodOfPkgType:" 16 | println(localInMethod1, s.Field1, s.Age) 17 | } 18 | 19 | func NewPkgType1(i int) *PkgType1 { 20 | var localInFunc1 = new(PkgType1) 21 | *localInFunc1 = PkgType1(i) 22 | return localInFunc1 23 | } 24 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/tags-demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type featureAttr struct { 6 | name string 7 | ver string // community, professional, ultimate 8 | } 9 | 10 | var featureList []featureAttr 11 | 12 | func init() { 13 | featureList = append(featureList, featureAttr{ 14 | name: "a", 15 | ver: "community", 16 | }) 17 | featureList = append(featureList, featureAttr{ 18 | name: "b", 19 | ver: "community", 20 | }) 21 | } 22 | 23 | func dumpFeatures() { 24 | fmt.Println("Features list:") 25 | for i, f := range featureList { 26 | fmt.Printf("\t%d: %s (%s)\n", i+1, f.name, f.ver) 27 | } 28 | } 29 | 30 | func main() { 31 | dumpFeatures() 32 | } 33 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/tags-demo/pro.go: -------------------------------------------------------------------------------- 1 | // +build professional ultimate 2 | 3 | package main 4 | 5 | func init() { 6 | featureList = append(featureList, featureAttr{ 7 | name: "c", 8 | ver: "professional", 9 | }) 10 | featureList = append(featureList, featureAttr{ 11 | name: "d", 12 | ver: "professional", 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/tags-demo/ultimate.go: -------------------------------------------------------------------------------- 1 | // +build ultimate 2 | 3 | package main 4 | 5 | func init() { 6 | featureList = append(featureList, featureAttr{ 7 | name: "e", 8 | ver: "ultimate", 9 | }) 10 | featureList = append(featureList, featureAttr{ 11 | name: "f", 12 | ver: "ultimate", 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/tags-demo/ultimate_win.go: -------------------------------------------------------------------------------- 1 | // +build ultimate,win 2 | 3 | package main 4 | 5 | func init() { 6 | featureList = append(featureList, featureAttr{ 7 | name: "g", 8 | ver: "ultimate(windows)", 9 | }) 10 | featureList = append(featureList, featureAttr{ 11 | name: "h", 12 | ver: "ultimate(windows)", 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/vet_assign.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | x := 1 5 | x = x 6 | println(x) 7 | } 8 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/vet_atomic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync/atomic" 4 | 5 | func main() { 6 | var x uint64 = 17 7 | x = atomic.AddUint64(&x, 1) 8 | //atomic.AddUint64(&x, 1) 9 | println(x) 10 | } 11 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/vet_bools.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var x, y int 5 | if x == y || x == y { 6 | println("ok") 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/vet_buildtag.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 tonybai.com 2 | 3 | // +building 4 | // +build !ignore 5 | 6 | package foo 7 | 8 | // +build pro 9 | 10 | var i = 5 11 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/vet_composites.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | ) 7 | 8 | type myFoo struct { 9 | name string 10 | age int 11 | } 12 | 13 | func main() { 14 | f := &myFoo{"tony", 20} 15 | err := &net.AddrError{"not found", "localhost"} 16 | fmt.Printf("%#v,%#v\n", *f, err) 17 | } 18 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/vet_copylocks.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | func foo(mu sync.Mutex) { 6 | mu.Lock() 7 | mu.Unlock() 8 | } 9 | 10 | func main() { 11 | var mu sync.Mutex 12 | foo(mu) 13 | mu1 := mu 14 | mu1.Lock() 15 | mu1.Unlock() 16 | 17 | pMu := &mu 18 | pMu1 := &mu1 19 | *pMu1 = *pMu 20 | } 21 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/vet_loopclosure.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "time" 4 | 5 | func main() { 6 | var s = []int{11, 12, 13, 14} 7 | for i, v := range s { 8 | go func() { 9 | println(i) 10 | println(v) 11 | }() 12 | } 13 | time.Sleep(5 * time.Second) 14 | } 15 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/vet_printf.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Printf("%s, %d", "hello") 7 | } 8 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/vet_unmarshal.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | type Foo struct { 8 | Name string 9 | Age int 10 | } 11 | 12 | func main() { 13 | var v Foo 14 | json.Unmarshal([]byte{}, v) 15 | } 16 | -------------------------------------------------------------------------------- /chapter10/sources/go-tools/vet_unsafeptr.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "unsafe" 4 | 5 | func main() { 6 | var x unsafe.Pointer 7 | var y uintptr 8 | x = unsafe.Pointer(y) 9 | _ = x 10 | } 11 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/channel_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var nilChan chan int 7 | nilChan <- 5 // 阻塞 8 | n := <-nilChan // 阻塞 9 | fmt.Println(n) 10 | 11 | var closedChan = make(chan int) 12 | close(closedChan) 13 | m := <-closedChan 14 | fmt.Println(m) // 0 15 | closedChan <- 5 // panic: send on closed channel 16 | } 17 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/for_range_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | fruits := []string{"banana", "apple", "mango"} 5 | 6 | // for fruit := range fruits { 7 | // println(fruit) 8 | // } 9 | for _, fruit := range fruits { 10 | println(fruit) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/for_range_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | for _, s := range "Hi,中国" { 7 | fmt.Printf("0x%X\n", s) 8 | } 9 | 10 | for _, b := range []byte("Hi,中国") { 11 | fmt.Printf("0x%X\n", b) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/for_range_3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | ) 7 | 8 | func main() { 9 | var indexes []int 10 | heros := map[int]string{ 11 | 1: "superman", 12 | 2: "batman", 13 | 3: "spiderman", 14 | 4: "the flash", 15 | } 16 | for k, v := range heros { 17 | indexes = append(indexes, k) 18 | fmt.Println(k, v) 19 | } 20 | 21 | sort.Ints(indexes) 22 | for _, idx := range indexes { 23 | fmt.Println(heros[idx]) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/for_range_4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var a = []int{1, 2, 3, 4, 5} 7 | var r = make([]int, 0) 8 | 9 | fmt.Println("a = ", a) 10 | 11 | for i, v := range a { 12 | if i == 0 { 13 | a = append(a, 6, 7) 14 | } 15 | 16 | r = append(r, v) 17 | } 18 | 19 | fmt.Println("r = ", r) 20 | fmt.Println("a = ", a) 21 | } 22 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/for_range_5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | var a = []int{1, 2, 3, 4, 5} 11 | var wg sync.WaitGroup 12 | 13 | for _, v := range a { 14 | wg.Add(1) 15 | go func() { 16 | time.Sleep(time.Second) 17 | fmt.Println(v) 18 | wg.Done() 19 | }() 20 | } 21 | wg.Wait() 22 | } 23 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/goroutine_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | c := make(chan error, 1) 10 | 11 | go func() { 12 | //do something 13 | time.Sleep(time.Second * 2) 14 | c <- nil // or c <- errors.New("some error") 15 | }() 16 | 17 | err := <-c 18 | fmt.Printf("sub goroutine exit with error: %v\n", err) 19 | } 20 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/goroutine_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "time" 4 | 5 | func main() { 6 | println("main goroutine: start to work...") 7 | go func() { 8 | println("goroutine1: start to work...") 9 | time.Sleep(50 * time.Microsecond) 10 | println("goroutine1: work done!") 11 | }() 12 | 13 | go func() { 14 | println("goroutine2: start to work...") 15 | time.Sleep(30 * time.Microsecond) 16 | println("goroutine2: work done!") 17 | }() 18 | 19 | println("main goroutine: work done!") 20 | } 21 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/goroutine_3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | var wg sync.WaitGroup 10 | wg.Add(2) 11 | println("main goroutine: start to work...") 12 | go func() { 13 | println("goroutine1: start to work...") 14 | time.Sleep(50 * time.Microsecond) 15 | println("goroutine1: work done!") 16 | wg.Done() 17 | }() 18 | 19 | go func() { 20 | println("goroutine2: start to work...") 21 | time.Sleep(30 * time.Microsecond) 22 | println("goroutine2: work done!") 23 | wg.Done() 24 | }() 25 | 26 | wg.Wait() 27 | println("main goroutine: work done!") 28 | } 29 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/goroutine_4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | var wg sync.WaitGroup 10 | wg.Add(2) 11 | println("main goroutine: start to work...") 12 | go func() { 13 | println("goroutine1: start to work...") 14 | time.Sleep(5 * time.Second) 15 | println("goroutine1: work done!") 16 | wg.Done() 17 | }() 18 | 19 | go func() { 20 | println("goroutine2: start to work...") 21 | time.Sleep(1 * time.Second) 22 | panic("division by zero") 23 | println("goroutine2: work done!") 24 | wg.Done() 25 | }() 26 | 27 | wg.Wait() 28 | println("main goroutine: work done!") 29 | } 30 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/goroutine_5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func safeRun(g func()) { 10 | defer func() { 11 | if e := recover(); e != nil { 12 | fmt.Println("caught a panic:", e) 13 | } 14 | }() 15 | 16 | g() 17 | } 18 | 19 | func main() { 20 | var wg sync.WaitGroup 21 | wg.Add(2) 22 | println("main goroutine: start to work...") 23 | go safeRun(func() { 24 | defer wg.Done() 25 | println("goroutine1: start to work...") 26 | time.Sleep(5 * time.Second) 27 | println("goroutine1: work done!") 28 | }) 29 | 30 | go safeRun(func() { 31 | defer wg.Done() 32 | println("goroutine2: start to work...") 33 | time.Sleep(1 * time.Second) 34 | panic("division by zero") 35 | println("goroutine2: work done!") 36 | }) 37 | 38 | wg.Wait() 39 | println("main goroutine: work done!") 40 | } 41 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/http_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | resp, err := http.Get("https://tip.golang.org") 11 | if err != nil { 12 | fmt.Println(err) 13 | return 14 | } 15 | defer resp.Body.Close() 16 | 17 | body, err := ioutil.ReadAll(resp.Body) 18 | if err != nil { 19 | fmt.Println(err) 20 | return 21 | } 22 | fmt.Println(string(body)) 23 | } 24 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/json_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "encoding/json" 4 | 5 | func main() { 6 | 7 | var nilSlice []int 8 | var emptySlice = make([]int, 0, 5) 9 | 10 | println(nilSlice == nil) // true 11 | println(emptySlice == nil) // false 12 | 13 | println(nilSlice, len(nilSlice), cap(nilSlice)) 14 | println(emptySlice, len(emptySlice), cap(emptySlice)) 15 | 16 | /* 17 | emptySlice = append(emptySlice, 1) 18 | println(emptySlice) 19 | */ 20 | 21 | m := map[string][]int{ 22 | "nilSlice": nilSlice, 23 | "emptySlice": emptySlice, 24 | } 25 | 26 | b, err := json.Marshal(m) 27 | if err != nil { 28 | println("json marshal error:", err) 29 | return 30 | } 31 | 32 | println(string(b)) 33 | } 34 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/json_3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | m := map[string]interface{}{ 10 | "byteSlice": []byte("hello, go"), 11 | "string": "hello, go", 12 | } 13 | 14 | b, _ := json.Marshal(m) 15 | fmt.Println(string(b)) 16 | } 17 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/method_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type foo struct { 6 | name string 7 | age int 8 | } 9 | 10 | func (f foo) setNameByValueReceiver(name string) { 11 | f.name = name 12 | } 13 | 14 | func (p *foo) setNameByPointerReceiver(name string) { 15 | p.name = name 16 | } 17 | 18 | func main() { 19 | f := foo{ 20 | name: "tony", 21 | age: 20, 22 | } 23 | fmt.Println(f) // {tony 20} 24 | 25 | f.setNameByValueReceiver("alex") 26 | fmt.Println(f) // {tony 20} 27 | f.setNameByPointerReceiver("alex") 28 | fmt.Println(f) // {alex 20} 29 | } 30 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/method_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type foo struct{} 4 | 5 | func (foo) methodWithValueReceiver() { 6 | println("methodWithValueReceiver invoke ok") 7 | } 8 | 9 | func (*foo) methodWithPointerReceiver() { 10 | println("methodWithPointerReceiver invoke ok") 11 | } 12 | 13 | type fooer interface { 14 | methodWithPointerReceiver() 15 | } 16 | 17 | func main() { 18 | f := foo{} 19 | pf := &f 20 | 21 | f.methodWithPointerReceiver() // 值类型实例调用采用指针类型receiver的方法 ok 22 | pf.methodWithValueReceiver() // 指针类型实例调用采用值类型receiver的方法 ok 23 | 24 | // var i fooer = f // 错误:f并未实现methodWithPointerReceiver 25 | var i fooer = pf // ok 26 | i.methodWithPointerReceiver() 27 | } 28 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/multi_variable_short_declaration.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var a int = 5 5 | b, c := "hello", 3.1415 6 | println(a, b, c) 7 | 8 | // var a int = 6 9 | // b, c := "world", 1.1 10 | 11 | println(&a, a) 12 | a, d := 55, "hello, go" // ok 13 | println(&a) 14 | println(a, d) 15 | } 16 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/nil_interface_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "strings" 6 | ) 7 | 8 | type TxtReader struct{} 9 | 10 | func (*TxtReader) Read(p []byte) (n int, err error) { 11 | // ... ... 12 | return 0, nil 13 | } 14 | 15 | func NewTxtReader(path string) io.Reader { 16 | var r *TxtReader 17 | if strings.Contains(path, ".txt") { 18 | r = new(TxtReader) 19 | } 20 | return r 21 | } 22 | 23 | func main() { 24 | i := NewTxtReader("/home/tony/test.png") 25 | if i == nil { 26 | println("fail to init txt reader") 27 | return 28 | } 29 | println("init txt reader ok") 30 | } 31 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/nil_interface_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | type TxtReader struct{} 8 | 9 | func (*TxtReader) Read(p []byte) (n int, err error) { 10 | // ... ... 11 | return 0, nil 12 | } 13 | 14 | func main() { 15 | var r *TxtReader = nil 16 | var i io.Reader = r 17 | println(i == nil) // false 18 | println(i) 19 | } 20 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/nil_type_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type foo struct { 6 | name string 7 | age int 8 | } 9 | 10 | func (*foo) doSomethingWithoutChange() { 11 | fmt.Println("doSomethingWithoutChange") 12 | } 13 | 14 | type MyInterface interface { 15 | doSomethingWithoutChange() 16 | } 17 | 18 | func main() { 19 | // 切片仅在调用append操作时才是零值可用的 20 | var strs []string = nil 21 | strs = append(strs, "hello", "go") 22 | fmt.Printf("%q\n", strs) 23 | 24 | // 自定义类型的方法中没有对自身实例进行解引用操作时, 25 | // 我们可以通过该类型的零值指针调用其方法 26 | var f *foo = nil 27 | f.doSomethingWithoutChange() 28 | 29 | // 给接口类型赋予显式转型后的nil(并非真正的零值) 30 | // 我们可以通过该接口调用没有解引用操作的方法 31 | var i MyInterface = (*foo)(nil) 32 | i.doSomethingWithoutChange() 33 | } 34 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/nil_type_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type foo struct { 6 | name string 7 | age int 8 | } 9 | 10 | func (f *foo) setName(name string) { 11 | f.name = name 12 | } 13 | 14 | func (*foo) doSomethingWithoutChange() { 15 | fmt.Println("doSomethingWithoutChange") 16 | } 17 | 18 | type MyInterface interface { 19 | doSomethingWithoutChange() 20 | } 21 | 22 | func main() { 23 | var strs []string = nil 24 | strs[0] = "go" // panic 25 | 26 | var m map[string]int 27 | m["key1"] = 1 // panic 28 | 29 | var f *foo = nil 30 | f.setName("tony") // panic 31 | 32 | var i MyInterface = nil 33 | i.doSomethingWithoutChange() // panic 34 | } 35 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/short_declaration_variable_shadowing_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var a int = 13 4 | 5 | func main() { 6 | println(a, &a) 7 | var a int = 23 8 | println(a, &a) 9 | 10 | if a == 23 { 11 | var a int = 33 12 | println(a, &a) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/short_declaration_variable_shadowing_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "errors" 4 | 5 | func foo() (int, error) { 6 | return 11, nil 7 | } 8 | 9 | func bar() (int, error) { 10 | return 21, errors.New("error in bar") 11 | } 12 | 13 | func main() { 14 | var err error 15 | defer func() { 16 | if err != nil { 17 | println("error in defer:", err.Error()) 18 | } 19 | }() 20 | 21 | a, err := foo() 22 | if err != nil { 23 | return 24 | } 25 | println("a=", a) 26 | 27 | if a == 11 { 28 | b, err := bar() 29 | if err != nil { 30 | return 31 | } 32 | println("b=", b) 33 | } 34 | println("no error occurs") 35 | } 36 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/short_declaration_variable_shadowing_3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "errors" 4 | 5 | func foo() (int, error) { 6 | return 11, nil 7 | } 8 | 9 | func bar() (int, error) { 10 | return 21, errors.New("error in bar") 11 | } 12 | 13 | func main() { 14 | var err error 15 | defer func() { 16 | if err != nil { 17 | println("error in defer:", err.Error()) 18 | } 19 | }() 20 | 21 | a, err := foo() 22 | if err != nil { 23 | return 24 | } 25 | println("a=", a) 26 | 27 | var b int 28 | if a == 11 { 29 | b, err = bar() 30 | if err != nil { 31 | return 32 | } 33 | println("b=", b) 34 | } 35 | println("no error occurs") 36 | } 37 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/slice_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func allocSlice(min, high int) []int { 6 | var b = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 99: 100} 7 | fmt.Printf("slice b: len(%d), cap(%d)\n", 8 | len(b), cap(b)) 9 | 10 | return b[min:high] 11 | } 12 | 13 | func main() { 14 | b1 := allocSlice(3, 7) 15 | fmt.Printf("slice b1: len(%d), cap(%d), elements(%v)\n", 16 | len(b1), cap(b1), b1) 17 | } 18 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/slice_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func allocSlice(min, high int) []int { 6 | var b = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 99: 100} 7 | fmt.Printf("slice b: len(%d), cap(%d)\n", 8 | len(b), cap(b)) 9 | nb := make([]int, high-min, high-min) 10 | copy(nb, b[min:high]) 11 | return nb 12 | } 13 | 14 | func main() { 15 | b1 := allocSlice(3, 7) 16 | fmt.Printf("slice b1: len(%d), cap(%d), elements(%v)\n", 17 | len(b1), cap(b1), b1) 18 | } 19 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/slice_3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func allocSlice(min, high int) []int { 9 | var b = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 10 | fmt.Printf("slice b: len(%d), cap(%d), elements(%v)\n", 11 | len(b), cap(b), b) 12 | 13 | go func() { 14 | time.Sleep(time.Second) 15 | fmt.Printf("slice b: len(%d), cap(%d), elements(%v)\n", 16 | len(b), cap(b), b) 17 | }() 18 | return b[min:high] 19 | } 20 | 21 | func main() { 22 | b1 := allocSlice(3, 7) 23 | fmt.Printf("slice b1: len(%d), cap(%d), elements(%v)\n", 24 | len(b1), cap(b1), b1) 25 | 26 | b2 := b1[:6] 27 | fmt.Printf("slice b2: len(%d), cap(%d), elements(%v)\n", 28 | len(b2), cap(b2), b2) 29 | 30 | b2[4] += 10 31 | b2[5] += 10 32 | 33 | time.Sleep(2 * time.Second) 34 | } 35 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/slice_4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func allocSlice(min, high int) []int { 6 | var b = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 7 | fmt.Printf("slice b: len(%d), cap(%d), elements(%v)\n", 8 | len(b), cap(b), b) 9 | 10 | nb := make([]int, high-min, high-min) 11 | copy(nb, b[min:high]) 12 | return nb 13 | } 14 | 15 | func main() { 16 | b1 := allocSlice(3, 7) 17 | fmt.Printf("slice b1: len(%d), cap(%d), elements(%v)\n", 18 | len(b1), cap(b1), b1) 19 | 20 | b2 := b1[:6] 21 | fmt.Printf("slice b2: len(%d), cap(%d), elements(%v)\n", 22 | len(b2), cap(b2), b2) 23 | } 24 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/string_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unicode/utf8" 6 | ) 7 | 8 | func main() { 9 | s := "大家好" 10 | fmt.Printf("字符串\"%s\"的长度为%d\n", s, len(s)) 11 | fmt.Printf("字符串\"%s\"中的字符个数%d\n", s, utf8.RuneCountInString(s)) 12 | 13 | s1 := "hello" 14 | fmt.Printf("s1[0] = %c\n", s1[0]) 15 | fmt.Printf("s1[1] = %c\n", s1[1]) 16 | // s[0] = 'j' // cannot assign to s[0] 17 | 18 | b := []byte(s1) 19 | b[0] = 'j' 20 | fmt.Printf("字符串s1 = %s\n", s1) 21 | fmt.Printf("切片b = %q\n", b) 22 | 23 | var s2 string 24 | fmt.Println(s2 == "") // true 25 | fmt.Println(len(s2) == 0) // true 26 | //fmt.Println(s2 == nil) // invalid operation: s2 == nil (mismatched types string and nil) 27 | 28 | } 29 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/switch.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int a = 1; 5 | switch(a) { 6 | case 0: 7 | printf("a = 0\n"); 8 | case 1: 9 | printf("a = 1\n"); 10 | case 2: 11 | printf("a = 2\n"); 12 | default: 13 | printf("a = N/A\n"); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/switch_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var a = 1 5 | switch a { 6 | case 0: 7 | println("a = 0") 8 | case 1: 9 | println("a = 1") 10 | case 2: 11 | println("a = 2") 12 | default: 13 | println("a = N/A") 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /chapter10/sources/go-trap/time_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | fmt.Println(time.Now().Format("%Y-%m-%d %H:%M:%S")) 10 | fmt.Println(time.Now().Format("2006年01月02日 15时04分05秒")) 11 | } 12 | -------------------------------------------------------------------------------- /chapter10/sources/tiny-image/Dockerfile: -------------------------------------------------------------------------------- 1 | From ubuntu:14.04 2 | 3 | RUN apt-get update \ 4 | && apt-get install -y software-properties-common \ 5 | && add-apt-repository ppa:gophers/archive \ 6 | && apt-get update \ 7 | && apt-get install -y golang-1.9-go \ 8 | git \ 9 | && rm -rf /var/lib/apt/lists/* 10 | 11 | ENV GOPATH /root/go 12 | ENV GOROOT /usr/lib/go-1.9 13 | ENV PATH="/usr/lib/go-1.9/bin:${PATH}" 14 | 15 | COPY ./httpserver.go /root/httpserver.go 16 | RUN go build -o /root/httpd /root/httpserver.go \ 17 | && chmod +x /root/httpd 18 | 19 | WORKDIR /root 20 | ENTRYPOINT ["/root/httpd"] 21 | -------------------------------------------------------------------------------- /chapter10/sources/tiny-image/Dockerfile.build: -------------------------------------------------------------------------------- 1 | FROM golang:1.9.2 2 | 3 | WORKDIR /go/src 4 | COPY ./httpserver.go . 5 | 6 | RUN go build -o httpd ./httpserver.go 7 | -------------------------------------------------------------------------------- /chapter10/sources/tiny-image/Dockerfile.build.alpine: -------------------------------------------------------------------------------- 1 | FROM golang:alpine 2 | 3 | WORKDIR /go/src 4 | COPY ./httpserver.go . 5 | 6 | RUN go build -o httpd ./httpserver.go 7 | -------------------------------------------------------------------------------- /chapter10/sources/tiny-image/Dockerfile.multistage: -------------------------------------------------------------------------------- 1 | FROM golang:alpine as builder 2 | 3 | WORKDIR /go/src 4 | COPY httpserver.go . 5 | 6 | RUN go build -o httpd ./httpserver.go 7 | 8 | 9 | From alpine:latest 10 | 11 | WORKDIR /root/ 12 | COPY --from=builder /go/src/httpd . 13 | RUN chmod +x /root/httpd 14 | 15 | ENTRYPOINT ["/root/httpd"] 16 | -------------------------------------------------------------------------------- /chapter10/sources/tiny-image/Dockerfile.target: -------------------------------------------------------------------------------- 1 | From ubuntu:14.04 2 | 3 | COPY ./httpd /root/httpd 4 | RUN chmod +x /root/httpd 5 | 6 | WORKDIR /root 7 | ENTRYPOINT ["/root/httpd"] 8 | -------------------------------------------------------------------------------- /chapter10/sources/tiny-image/Dockerfile.target.alpine: -------------------------------------------------------------------------------- 1 | From alpine 2 | 3 | COPY ./httpd /root/httpd 4 | RUN chmod +x /root/httpd 5 | 6 | WORKDIR /root 7 | ENTRYPOINT ["/root/httpd"] 8 | -------------------------------------------------------------------------------- /chapter10/sources/tiny-image/httpserver.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("http daemon start") 10 | fmt.Println(" -> listen on port:8080") 11 | http.ListenAndServe(":8080", nil) 12 | } 13 | -------------------------------------------------------------------------------- /chapter2/sources/GoLibProj/LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoLibProj/LICENSE -------------------------------------------------------------------------------- /chapter2/sources/GoLibProj/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoLibProj/Makefile -------------------------------------------------------------------------------- /chapter2/sources/GoLibProj/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoLibProj/README.md -------------------------------------------------------------------------------- /chapter2/sources/GoLibProj/go.mod: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoLibProj/go.mod -------------------------------------------------------------------------------- /chapter2/sources/GoLibProj/internal/ilib1/ilib1.go: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoLibProj/internal/ilib1/ilib1.go -------------------------------------------------------------------------------- /chapter2/sources/GoLibProj/internal/ilib2/ilib2.go: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoLibProj/internal/ilib2/ilib2.go -------------------------------------------------------------------------------- /chapter2/sources/GoLibProj/lib.go: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoLibProj/lib.go -------------------------------------------------------------------------------- /chapter2/sources/GoLibProj/lib1/lib1.go: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoLibProj/lib1/lib1.go -------------------------------------------------------------------------------- /chapter2/sources/GoLibProj/lib2/lib2.go: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoLibProj/lib2/lib2.go -------------------------------------------------------------------------------- /chapter2/sources/GoProj/LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoProj/LICENSE -------------------------------------------------------------------------------- /chapter2/sources/GoProj/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoProj/Makefile -------------------------------------------------------------------------------- /chapter2/sources/GoProj/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoProj/README.md -------------------------------------------------------------------------------- /chapter2/sources/GoProj/cmd/app1/main.go: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoProj/cmd/app1/main.go -------------------------------------------------------------------------------- /chapter2/sources/GoProj/cmd/app2/main.go: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoProj/cmd/app2/main.go -------------------------------------------------------------------------------- /chapter2/sources/GoProj/go.mod: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoProj/go.mod -------------------------------------------------------------------------------- /chapter2/sources/GoProj/pkg/lib1/lib1.go: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoProj/pkg/lib1/lib1.go -------------------------------------------------------------------------------- /chapter2/sources/GoProj/pkg/lib2/lib2.go: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter2/sources/GoProj/pkg/lib2/lib2.go -------------------------------------------------------------------------------- /chapter2/sources/gofmt_demo.go: -------------------------------------------------------------------------------- 1 | // 注意:这不是一个可以编译通过的源文件,仅用于gofmt演示 2 | package main 3 | 4 | import "fmt" 5 | 6 | func main() { 7 | fmt.Println(s[3:len(s)]) 8 | n, err := s.r.Read(s.buf[3:len(s.buf)]) 9 | reverseLabels = append(reverseLabels, domain[3:len(domain)]) 10 | reverseLabels = append(reverseLabels, domain[i+1:len(domain)]) 11 | } 12 | -------------------------------------------------------------------------------- /chapter3/sources/bytes_buffer_write.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | var b bytes.Buffer 10 | b.Write([]byte("Effective Go")) 11 | fmt.Println(b.String()) 12 | } 13 | -------------------------------------------------------------------------------- /chapter3/sources/call_method_through_nil_pointer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | ) 7 | 8 | func main() { 9 | var p *net.TCPAddr 10 | fmt.Println(p) 11 | } 12 | -------------------------------------------------------------------------------- /chapter3/sources/control_structure_idiom_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func demo1() { 9 | var m = [...]int{1, 2, 3, 4, 5} 10 | 11 | for i, v := range m { 12 | go func() { 13 | time.Sleep(time.Second * 3) 14 | fmt.Println(i, v) 15 | }() 16 | } 17 | 18 | time.Sleep(time.Second * 10) 19 | } 20 | 21 | func demo2() { 22 | var m = [...]int{1, 2, 3, 4, 5} 23 | 24 | for i, v := range m { 25 | go func(i, v int) { 26 | time.Sleep(time.Second * 3) 27 | fmt.Println(i, v) 28 | }(i, v) 29 | } 30 | 31 | time.Sleep(time.Second * 10) 32 | } 33 | 34 | func main() { 35 | demo1() 36 | demo2() 37 | } 38 | -------------------------------------------------------------------------------- /chapter3/sources/control_structure_idiom_3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var s = "中国人" 7 | 8 | for i, v := range s { 9 | fmt.Printf("%d %s 0x%x\n", i, string(v), v) 10 | } 11 | fmt.Println("") 12 | 13 | //byte sequence of s: 0xe4 0xb8 0xad 0xe5 0x9b 0xbd 0xe4 0xba 0xba 14 | var sl = []byte{0xe4, 0xb8, 0xad, 0xe5, 0x9b, 0xbd, 0xe4, 0xba, 0xba} 15 | for _, v := range sl { 16 | fmt.Printf("0x%x ", v) 17 | } 18 | fmt.Println("\n") 19 | 20 | sl[3] = 0xd0 21 | sl[4] = 0xd6 22 | sl[5] = 0xb9 23 | 24 | for i, v := range string(sl) { 25 | fmt.Printf("%d %x\n", i, v) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /chapter3/sources/control_structure_idiom_4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var m = map[string]int{ 7 | "tony": 21, 8 | "tom": 22, 9 | "jim": 23, 10 | } 11 | 12 | for k, v := range m { 13 | fmt.Println(k, v) 14 | } 15 | fmt.Println("\n") 16 | 17 | counter := 0 18 | for k, v := range m { 19 | if counter == 0 { 20 | delete(m, "tony") 21 | } 22 | counter++ 23 | fmt.Println(k, v) 24 | } 25 | fmt.Println("counter is ", counter) 26 | fmt.Println("\n") 27 | 28 | m["tony"] = 21 29 | counter = 0 30 | 31 | for k, v := range m { 32 | if counter == 0 { 33 | m["lucy"] = 24 34 | } 35 | counter++ 36 | fmt.Println(k, v) 37 | } 38 | fmt.Println("counter is ", counter) 39 | } 40 | -------------------------------------------------------------------------------- /chapter3/sources/control_structure_idiom_5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func recvFromUnbufferedChannel() { 9 | var c = make(chan int) 10 | 11 | go func() { 12 | time.Sleep(time.Second * 3) 13 | c <- 1 14 | c <- 2 15 | c <- 3 16 | close(c) 17 | }() 18 | 19 | for v := range c { 20 | fmt.Println(v) 21 | } 22 | } 23 | 24 | func recvFromNilChannel() { 25 | var c chan int 26 | 27 | // 程序将一直阻塞在这里 28 | for v := range c { 29 | fmt.Println(v) 30 | } 31 | 32 | } 33 | 34 | func main() { 35 | recvFromUnbufferedChannel() 36 | recvFromNilChannel() 37 | } 38 | -------------------------------------------------------------------------------- /chapter3/sources/control_structure_idiom_6.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | exit := make(chan interface{}) 10 | 11 | go func() { 12 | for { 13 | select { 14 | case <-time.After(time.Second): 15 | fmt.Println("tick") 16 | case <-exit: 17 | fmt.Println("exiting...") 18 | break 19 | } 20 | } 21 | fmt.Println("exit!") 22 | }() 23 | 24 | time.Sleep(3 * time.Second) 25 | exit <- struct{}{} 26 | 27 | // wait child goroutine exit 28 | time.Sleep(3 * time.Second) 29 | } 30 | -------------------------------------------------------------------------------- /chapter3/sources/control_structure_idiom_7.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | exit := make(chan interface{}) 10 | 11 | go func() { 12 | loop: 13 | for { 14 | select { 15 | case <-time.After(time.Second): 16 | fmt.Println("tick") 17 | case <-exit: 18 | fmt.Println("exiting...") 19 | break loop 20 | } 21 | } 22 | fmt.Println("exit!") 23 | }() 24 | 25 | time.Sleep(3 * time.Second) 26 | exit <- struct{}{} 27 | 28 | // wait child goroutine exit 29 | time.Sleep(3 * time.Second) 30 | } 31 | -------------------------------------------------------------------------------- /chapter3/sources/evaluation_order_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var ( 6 | a = c + b 7 | b = f() 8 | c = f() 9 | d = 3 10 | ) 11 | 12 | func f() int { 13 | d++ 14 | return d 15 | } 16 | 17 | func main() { 18 | fmt.Println(a, b, c, d) 19 | } 20 | -------------------------------------------------------------------------------- /chapter3/sources/evaluation_order_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var ( 6 | a = c + b 7 | b = f() 8 | _ = f() 9 | c = f() 10 | d = 3 11 | ) 12 | 13 | func f() int { 14 | d++ 15 | return d 16 | } 17 | 18 | func main() { 19 | fmt.Println(a, b, c, d) 20 | } 21 | -------------------------------------------------------------------------------- /chapter3/sources/evaluation_order_3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var ( 6 | a = c 7 | b, c = f() 8 | d = 3 9 | ) 10 | 11 | func f() (int, int) { 12 | d++ 13 | return d, d + 1 14 | } 15 | 16 | func main() { 17 | fmt.Println(a, b, c, d) 18 | } 19 | -------------------------------------------------------------------------------- /chapter3/sources/evaluation_order_4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func f() int { 6 | fmt.Println("calling f") 7 | return 1 8 | } 9 | func g(a, b, c int) int { 10 | fmt.Println("calling g") 11 | return 2 12 | } 13 | func h() int { 14 | fmt.Println("calling h") 15 | return 3 16 | } 17 | 18 | func i() int { 19 | fmt.Println("calling i") 20 | return 1 21 | } 22 | 23 | func j() int { 24 | fmt.Println("calling j") 25 | return 1 26 | } 27 | func k() bool { 28 | fmt.Println("calling k") 29 | return true 30 | } 31 | 32 | func main() { 33 | var y = []int{11, 12, 13} 34 | var x = []int{21, 22, 23} 35 | 36 | var c chan int = make(chan int) 37 | go func() { 38 | c <- 1 39 | }() 40 | 41 | y[f()], _ = g(h(), i()+x[j()], <-c), k() 42 | } 43 | -------------------------------------------------------------------------------- /chapter3/sources/evaluation_order_5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var a, b, c = f() + v(), g(), sqr(u()) + v() 6 | 7 | func f() int { 8 | fmt.Println("calling f") 9 | return c 10 | } 11 | func g() int { 12 | 13 | fmt.Println("calling g") 14 | return 1 15 | } 16 | func sqr(x int) int { 17 | fmt.Println("calling sqr") 18 | return x * x 19 | } 20 | 21 | func v() int { 22 | fmt.Println("calling v") 23 | return 1 24 | } 25 | 26 | func u() int { 27 | fmt.Println("calling u") 28 | return 2 29 | } 30 | 31 | func main() { 32 | fmt.Println(a, b, c) 33 | } 34 | -------------------------------------------------------------------------------- /chapter3/sources/evaluation_order_6.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func example() { 6 | n0, n1 := 1, 2 7 | n0, n1 = n0+n1, n0 8 | fmt.Println(n0, n1) 9 | } 10 | 11 | func main() { 12 | example() 13 | } 14 | -------------------------------------------------------------------------------- /chapter3/sources/evaluation_order_7.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Expr(n int) int { 6 | fmt.Println(n) 7 | return n 8 | } 9 | 10 | func main() { 11 | switch Expr(2) { 12 | case Expr(1), Expr(2), Expr(3): 13 | fmt.Println("enter into case1") 14 | fallthrough 15 | case Expr(4): 16 | fmt.Println("enter into case2") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter3/sources/for_range_bench_test.go: -------------------------------------------------------------------------------- 1 | package array_test 2 | 3 | import "testing" 4 | 5 | var a [100]int 6 | var sl = a[:] 7 | 8 | func arrayRangeLoop() { 9 | var sum int 10 | for _, n := range a { 11 | sum += n 12 | } 13 | } 14 | 15 | func pointerToArrayRangeLoop() { 16 | var sum int 17 | for _, n := range &a { 18 | sum += n 19 | } 20 | } 21 | 22 | func sliceRangeLoop() { 23 | var sum int 24 | for _, n := range sl { 25 | sum += n 26 | } 27 | } 28 | 29 | func BenchmarkArrayRangeLoop(b *testing.B) { 30 | for i := 0; i < b.N; i++ { 31 | arrayRangeLoop() 32 | } 33 | } 34 | func BenchmarkPointerToArrayRangeLoop(b *testing.B) { 35 | for i := 0; i < b.N; i++ { 36 | pointerToArrayRangeLoop() 37 | } 38 | } 39 | func BenchmarkSliceRangeLoop(b *testing.B) { 40 | for i := 0; i < b.N; i++ { 41 | sliceRangeLoop() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /chapter3/sources/item16-demo/chapter3-demo1/cmd/app1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/bigwhite/effective-go-book/chapter2-demo1/pkg/pkg1" 5 | ) 6 | 7 | func main() { 8 | pkg1.Func1() 9 | } 10 | -------------------------------------------------------------------------------- /chapter3/sources/item16-demo/chapter3-demo1/cmd/app2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | mypkg2 "github.com/bigwhite/effective-go-book/chapter2-demo1/pkg/pkg2" 5 | ) 6 | 7 | func main() { 8 | mypkg2.Func1() 9 | } 10 | -------------------------------------------------------------------------------- /chapter3/sources/item16-demo/chapter3-demo1/cmd/app3/app3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter3/sources/item16-demo/chapter3-demo1/cmd/app3/app3 -------------------------------------------------------------------------------- /chapter3/sources/item16-demo/chapter3-demo1/cmd/app3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | pkg1 "github.com/bigwhite/effective-go-book/chapter2-demo1/pkg/pkg1" 5 | mypkg1 "github.com/bigwhite/effective-go-book/chapter2-demo2/pkg/pkg1" 6 | ) 7 | 8 | func main() { 9 | pkg1.Func1() 10 | mypkg1.Func1() 11 | } 12 | -------------------------------------------------------------------------------- /chapter3/sources/item16-demo/chapter3-demo1/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/effective-go-book/chapter2-demo1 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /chapter3/sources/item16-demo/chapter3-demo1/pkg/pkg1/pkg1.go: -------------------------------------------------------------------------------- 1 | package pkg1 2 | 3 | import "fmt" 4 | 5 | func Func1() { 6 | fmt.Println("pkg1.Func1 invoked") 7 | } 8 | -------------------------------------------------------------------------------- /chapter3/sources/item16-demo/chapter3-demo1/pkg/pkg2/pkg2.go: -------------------------------------------------------------------------------- 1 | package mypkg2 2 | 3 | import "fmt" 4 | 5 | func Func1() { 6 | fmt.Println("mypkg2.Func1 invoked") 7 | } 8 | -------------------------------------------------------------------------------- /chapter3/sources/item16-demo/chapter3-demo2/pkg/pkg1/pkg1.go: -------------------------------------------------------------------------------- 1 | package pkg1 2 | 3 | import "fmt" 4 | 5 | func Func1() { 6 | fmt.Println("pkg1.Func1 invoked") 7 | } 8 | -------------------------------------------------------------------------------- /chapter3/sources/map_concurrent_read_and_write.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func doIteration(m map[int]int) { 9 | for k, v := range m { 10 | _ = fmt.Sprintf("[%d, %d] ", k, v) 11 | } 12 | } 13 | func doWrite(m map[int]int) { 14 | for k, v := range m { 15 | m[k] = v + 1 16 | } 17 | } 18 | 19 | func main() { 20 | m := map[int]int{ 21 | 1: 11, 22 | 2: 12, 23 | 3: 13, 24 | } 25 | 26 | go func() { 27 | for i := 0; i < 1000; i++ { 28 | doIteration(m) 29 | } 30 | }() 31 | 32 | go func() { 33 | for i := 0; i < 1000; i++ { 34 | doWrite(m) 35 | } 36 | }() 37 | 38 | time.Sleep(5 * time.Second) 39 | } 40 | -------------------------------------------------------------------------------- /chapter3/sources/map_iterate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | m := map[int]int{ 7 | 1: 11, 8 | 2: 12, 9 | 3: 13, 10 | } 11 | 12 | fmt.Printf("{ ") 13 | for k, v := range m { 14 | fmt.Printf("[%d, %d] ", k, v) 15 | } 16 | fmt.Printf("}\n") 17 | } 18 | -------------------------------------------------------------------------------- /chapter3/sources/map_multiple_iterate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func doIteration(m map[int]int) { 6 | fmt.Printf("{ ") 7 | for k, v := range m { 8 | fmt.Printf("[%d, %d] ", k, v) 9 | } 10 | fmt.Printf("}\n") 11 | } 12 | 13 | func main() { 14 | m := map[int]int{ 15 | 1: 11, 16 | 2: 12, 17 | 3: 13, 18 | } 19 | 20 | for i := 0; i < 3; i++ { 21 | doIteration(m) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /chapter3/sources/map_stable_iterate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func doIteration(sl []int, m map[int]int) { 6 | fmt.Printf("{ ") 7 | for _, k := range sl { 8 | v, ok := m[k] 9 | if !ok { 10 | continue 11 | } 12 | fmt.Printf("[%d, %d] ", k, v) 13 | } 14 | fmt.Printf("}\n") 15 | } 16 | 17 | func main() { 18 | var sl []int 19 | m := map[int]int{ 20 | 1: 11, 21 | 2: 12, 22 | 3: 13, 23 | } 24 | 25 | for k, _ := range m { 26 | sl = append(sl, k) 27 | } 28 | 29 | for i := 0; i < 3; i++ { 30 | doIteration(sl, m) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter3/sources/map_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | const mapSize = 10000 6 | 7 | func BenchmarkMapInitWithoutCap(b *testing.B) { 8 | for n := 0; n < b.N; n++ { 9 | m := make(map[int]int) 10 | for i := 0; i < mapSize; i++ { 11 | m[i] = i 12 | } 13 | } 14 | } 15 | 16 | func BenchmarkMapInitWithCap(b *testing.B) { 17 | for n := 0; n < b.N; n++ { 18 | m := make(map[int]int, mapSize) 19 | for i := 0; i < mapSize; i++ { 20 | m[i] = i 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /chapter3/sources/map_var_as_param.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func foo(m map[string]int) { 6 | m["key1"] = 11 7 | m["key2"] = 12 8 | } 9 | 10 | func main() { 11 | m := map[string]int{ 12 | "key1": 1, 13 | "key2": 2, 14 | } 15 | 16 | fmt.Println(m) 17 | foo(m) 18 | fmt.Println(m) 19 | } 20 | -------------------------------------------------------------------------------- /chapter3/sources/slice_append.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var s []int 7 | s = append(s, 1) 8 | fmt.Println(len(s), cap(s)) 9 | s = append(s, 2) 10 | fmt.Println(len(s), cap(s)) 11 | s = append(s, 3) 12 | fmt.Println(len(s), cap(s)) 13 | s = append(s, 4) 14 | fmt.Println(len(s), cap(s)) 15 | s = append(s, 5) 16 | fmt.Println(len(s), cap(s)) 17 | } 18 | -------------------------------------------------------------------------------- /chapter3/sources/slice_benchmark_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | const sliceSize = 10000 6 | 7 | func BenchmarkSliceInitWithoutCap(b *testing.B) { 8 | for n := 0; n < b.N; n++ { 9 | sl := make([]int, 0) 10 | for i := 0; i < sliceSize; i++ { 11 | sl = append(sl, i) 12 | } 13 | } 14 | } 15 | 16 | func BenchmarkSliceInitWithCap(b *testing.B) { 17 | for n := 0; n < b.N; n++ { 18 | sl := make([]int, 0, sliceSize) 19 | for i := 0; i < sliceSize; i++ { 20 | sl = append(sl, i) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /chapter3/sources/string_as_param_benchmark_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var s string = `Go, also known as Golang, is a statically typed, compiled programming language designed at Google by Robert Griesemer, Rob Pike, and Ken Thompson. Go is syntactically similar to C, but with memory safety, garbage collection, structural typing, and communicating sequential processes (CSP)-style concurrency.` 8 | 9 | func handleString(s string) { 10 | _ = s + "hello" 11 | } 12 | 13 | func handlePtrToString(s *string) { 14 | _ = *s + "hello" 15 | 16 | } 17 | 18 | func BenchmarkHandleString(b *testing.B) { 19 | for n := 0; n < b.N; n++ { 20 | handleString(s) 21 | } 22 | } 23 | func BenchmarkHandlePtrToString(b *testing.B) { 24 | for n := 0; n < b.N; n++ { 25 | handlePtrToString(&s) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /chapter3/sources/string_compare.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // == 7 | s1 := "世界和平" 8 | s2 := "世界" + "和平" 9 | fmt.Println(s1 == s2) // true 10 | 11 | // != 12 | s1 = "Go" 13 | s2 = "C" 14 | fmt.Println(s1 != s2) // true 15 | 16 | // < and <= 17 | s1 = "12345" 18 | s2 = "23456" 19 | fmt.Println(s1 < s2) // true 20 | fmt.Println(s1 <= s2) // true 21 | 22 | // > and >= 23 | s1 = "12345" 24 | s2 = "123" 25 | fmt.Println(s1 > s2) // true 26 | fmt.Println(s1 >= s2) // true 27 | } 28 | -------------------------------------------------------------------------------- /chapter3/sources/string_for_range_covert_optimize.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func convert() { 9 | s := "中国欢迎您,北京欢迎您" 10 | sl := []byte(s) 11 | for _, v := range sl { 12 | _ = v 13 | } 14 | } 15 | func convertWithOptimize() { 16 | s := "中国欢迎您,北京欢迎您" 17 | for _, v := range []byte(s) { 18 | _ = v 19 | } 20 | } 21 | 22 | func main() { 23 | fmt.Println(testing.AllocsPerRun(1, convert)) 24 | fmt.Println(testing.AllocsPerRun(1, convertWithOptimize)) 25 | } 26 | -------------------------------------------------------------------------------- /chapter3/sources/string_immutable1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | // original string 9 | var s string = "hello" 10 | fmt.Println("original string:", s) 11 | 12 | // reslice it and try to change the original string 13 | sl := []byte(s) 14 | sl[0] = 't' 15 | fmt.Println("slice:", string(sl)) 16 | fmt.Println("after reslice, the original string is:", string(s)) 17 | } 18 | -------------------------------------------------------------------------------- /chapter3/sources/string_immutable2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | // original string 10 | var s string = "hello" 11 | fmt.Println("original string:", s) 12 | 13 | // try to change the original string through unsafe pointer 14 | modifyString(&s) 15 | fmt.Println(s) 16 | } 17 | 18 | func modifyString(s *string) { 19 | // 取出第一个8字节的值 20 | p := (*uintptr)(unsafe.Pointer(s)) 21 | 22 | // 获取底层数组的地址 23 | var array *[5]byte = (*[5]byte)(unsafe.Pointer(*p)) 24 | 25 | var len *int = (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(s)) + unsafe.Sizeof((*uintptr)(nil)))) 26 | 27 | for i := 0; i < (*len); i++ { 28 | fmt.Printf("%p => %c\n", &((*array)[i]), (*array)[i]) 29 | p1 := &((*array)[i]) 30 | v := (*p1) 31 | (*p1) = v + 1 //try to change the character 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /chapter3/sources/string_mallocs_in_convert.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func byteSliceToString() { 9 | sl := []byte{ 10 | 0xE4, 0xB8, 0xAD, 11 | 0xE5, 0x9B, 0xBD, 12 | 0xE6, 0xAC, 0xA2, 13 | 0xE8, 0xBF, 0x8E, 14 | 0xE6, 0x82, 0xA8, 15 | 0xEF, 0xBC, 0x8C, 16 | 0xE5, 0x8C, 0x97, 17 | 0xE4, 0xBA, 0xAC, 18 | 0xE6, 0xAC, 0xA2, 19 | 0xE8, 0xBF, 0x8E, 20 | 0xE6, 0x82, 0xA8, 21 | } 22 | 23 | _ = string(sl) 24 | } 25 | 26 | func stringToByteSlice() { 27 | s := "中国欢迎您,北京换欢您" 28 | _ = []byte(s) 29 | } 30 | 31 | func main() { 32 | fmt.Println(testing.AllocsPerRun(1, byteSliceToString)) 33 | fmt.Println(testing.AllocsPerRun(1, stringToByteSlice)) 34 | } 35 | -------------------------------------------------------------------------------- /chapter3/sources/string_multilines.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | const s = `好雨知时节,当春乃发生。 6 | 随风潜入夜,润物细无声。 7 | 野径云俱黑,江船火独明。 8 | 晓看红湿处,花重锦官城。` 9 | 10 | func main() { 11 | fmt.Println(s) 12 | } 13 | -------------------------------------------------------------------------------- /chapter3/sources/string_nonascii.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // 中文字符 Unicode CodePoint(码点) UTF8编码 7 | // 中 U+4E2D E4B8AD 8 | // 国 U+56FD E59BBD 9 | // 欢 U+6B22 E6ACA2 10 | // 迎 U+8FCE E8BF8E 11 | // 您 U+60A8 E682A8 12 | s := "中国欢迎您" 13 | rs := []rune(s) 14 | sl := []byte(s) 15 | for i, v := range rs { 16 | var utf8Bytes []byte 17 | for j := i * 3; j < (i+1)*3; j++ { 18 | utf8Bytes = append(utf8Bytes, sl[j]) 19 | } 20 | fmt.Printf("%s => %X => %X\n", string(v), v, utf8Bytes) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /chapter3/sources/string_slice_to_string.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | rs := []rune{ 7 | 0x4E2D, 8 | 0x56FD, 9 | 0x6B22, 10 | 0x8FCE, 11 | 0x60A8, 12 | } 13 | 14 | s := string(rs) 15 | fmt.Println(s) // 中国欢迎您 16 | 17 | sl := []byte{ 18 | 0xE4, 0xB8, 0xAD, 19 | 0xE5, 0x9B, 0xBD, 20 | 0xE6, 0xAC, 0xA2, 21 | 0xE8, 0xBF, 0x8E, 22 | 0xE6, 0x82, 0xA8, 23 | } 24 | 25 | s = string(sl) 26 | fmt.Println(s) // 中国欢迎您 27 | } 28 | -------------------------------------------------------------------------------- /chapter3/sources/string_type.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | const ( 6 | s = "string constant" 7 | ) 8 | 9 | func main() { 10 | var s1 string = "string variable" 11 | 12 | fmt.Printf("%T\n", s) // string 13 | fmt.Printf("%T\n", s1) // string 14 | fmt.Printf("%T\n", "temporary string literal") // string 15 | } 16 | -------------------------------------------------------------------------------- /chapter3/sources/varinit.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int cnt; 4 | 5 | void f() { 6 | int n; 7 | printf("local n = %d\n", n); 8 | 9 | if (cnt > 5) { 10 | return; 11 | } 12 | 13 | cnt++; 14 | f(); 15 | } 16 | 17 | int main() { 18 | f(); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /chapter4/sources/.gitkeeper: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter4/sources/.gitkeeper -------------------------------------------------------------------------------- /chapter4/sources/call_init_in_main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func init() { 6 | fmt.Println("init invoked") 7 | } 8 | 9 | func main() { 10 | init() 11 | } 12 | -------------------------------------------------------------------------------- /chapter4/sources/defer_perf_benchmark_1_test.go: -------------------------------------------------------------------------------- 1 | package defer_test 2 | 3 | import "testing" 4 | 5 | func sum(max int) int { 6 | total := 0 7 | for i := 0; i < max; i++ { 8 | total += i 9 | } 10 | 11 | return total 12 | } 13 | 14 | func fooWithDefer() { 15 | defer func() { 16 | sum(10) 17 | }() 18 | } 19 | func fooWithoutDefer() { 20 | sum(10) 21 | } 22 | 23 | func BenchmarkFooWithDefer(b *testing.B) { 24 | for i := 0; i < b.N; i++ { 25 | fooWithDefer() 26 | } 27 | } 28 | func BenchmarkFooWithoutDefer(b *testing.B) { 29 | for i := 0; i < b.N; i++ { 30 | fooWithoutDefer() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter4/sources/deferred_func_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "sync" 7 | ) 8 | 9 | func writeToFile(fname string, data []byte, mu *sync.Mutex) error { 10 | mu.Lock() 11 | defer mu.Unlock() 12 | f, err := os.OpenFile(fname, os.O_RDWR, 0666) 13 | if err != nil { 14 | return err 15 | } 16 | defer f.Close() 17 | 18 | _, err = f.Seek(0, 2) 19 | if err != nil { 20 | return err 21 | } 22 | 23 | _, err = f.Write(data) 24 | if err != nil { 25 | return err 26 | } 27 | 28 | return f.Sync() 29 | } 30 | 31 | func main() { 32 | var mu sync.Mutex 33 | err := writeToFile("./foo.txt", []byte("hello, defer!\n"), &mu) 34 | if err != nil { 35 | fmt.Println("writeToFile error:", err) 36 | return 37 | } 38 | fmt.Println("writeToFile ok") 39 | } 40 | -------------------------------------------------------------------------------- /chapter4/sources/deferred_func_3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func bar() { 6 | fmt.Println("raise a panic") 7 | panic(-1) 8 | } 9 | 10 | func foo() { 11 | defer func() { 12 | if e := recover(); e != nil { 13 | fmt.Println("recovered from a panic") 14 | } 15 | }() 16 | bar() 17 | } 18 | 19 | func main() { 20 | foo() 21 | fmt.Println("main exit normally") 22 | } 23 | -------------------------------------------------------------------------------- /chapter4/sources/deferred_func_4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //#include 4 | // void crash() { 5 | // int *q = NULL; 6 | // (*q) = 15000; 7 | // printf("%d\n", *q); 8 | // } 9 | import "C" 10 | 11 | import ( 12 | "fmt" 13 | ) 14 | 15 | func bar() { 16 | C.crash() 17 | } 18 | 19 | func foo() { 20 | defer func() { 21 | if e := recover(); e != nil { 22 | fmt.Println("recovered from a panic:", e) 23 | } 24 | }() 25 | bar() 26 | } 27 | 28 | func main() { 29 | foo() 30 | fmt.Println("main exit normally") 31 | } 32 | -------------------------------------------------------------------------------- /chapter4/sources/deferred_func_5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func foo(a, b int) (x, y int) { 6 | defer func() { 7 | x = x * 5 8 | y = y * 10 9 | }() 10 | 11 | x = a + 5 12 | y = b + 6 13 | return 14 | } 15 | 16 | func main() { 17 | x, y := foo(1, 2) 18 | fmt.Println("x=", x, "y=", y) 19 | } 20 | -------------------------------------------------------------------------------- /chapter4/sources/deferred_func_6.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func bar() (int, int) { 4 | return 1, 2 5 | } 6 | 7 | func foo() { 8 | // builtin functions: 9 | // append cap close complex copy delete imag len 10 | // make new panic print println real recover 11 | 12 | var c chan int 13 | var sl []int 14 | var m = make(map[string]int, 10) 15 | m["item1"] = 1 16 | m["item2"] = 2 17 | var a = complex(1.0, -1.4) 18 | 19 | var sl1 []int 20 | 21 | defer bar() 22 | defer append(sl, 11) 23 | defer cap(sl) 24 | defer close(c) 25 | defer complex(2, -2) 26 | defer copy(sl1, sl) 27 | defer delete(m, "item2") 28 | defer imag(a) 29 | defer len(sl) 30 | defer make([]int, 10) 31 | defer new(*int) 32 | defer panic(1) 33 | defer print("hello, defer\n") 34 | defer println("hello, defer") 35 | defer real(a) 36 | defer recover() 37 | } 38 | 39 | func main() { 40 | foo() 41 | } 42 | -------------------------------------------------------------------------------- /chapter4/sources/deferred_func_7.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func foo1() { 6 | for i := 0; i <= 3; i++ { 7 | defer fmt.Println(i) 8 | } 9 | } 10 | 11 | func foo2() { 12 | for i := 0; i <= 3; i++ { 13 | defer func(n int) { 14 | fmt.Println(n) 15 | }(i) 16 | } 17 | } 18 | 19 | func foo3() { 20 | for i := 0; i <= 3; i++ { 21 | defer func() { 22 | fmt.Println(i) 23 | }() 24 | } 25 | } 26 | 27 | func main() { 28 | fmt.Println("foo1 result:") 29 | foo1() 30 | fmt.Println("\nfoo2 result:") 31 | foo2() 32 | fmt.Println("\nfoo3 result:") 33 | foo3() 34 | } 35 | -------------------------------------------------------------------------------- /chapter4/sources/deferred_func_8.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func foo1() { 6 | sl := []int{1, 2, 3} 7 | defer func(a []int) { 8 | fmt.Println(a) 9 | }(sl) 10 | 11 | sl = []int{3, 2, 1} 12 | _ = sl 13 | } 14 | func foo2() { 15 | sl := []int{1, 2, 3} 16 | defer func(p *[]int) { 17 | fmt.Println(*p) 18 | }(&sl) 19 | 20 | sl = []int{3, 2, 1} 21 | _ = sl 22 | } 23 | 24 | func main() { 25 | foo1() 26 | foo2() 27 | } 28 | -------------------------------------------------------------------------------- /chapter4/sources/function_as_first_class_citizen_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type binaryCalcFunc func(int, int) int 6 | 7 | func main() { 8 | var i interface{} = binaryCalcFunc(func(x, y int) int { return x + y }) 9 | c := make(chan func(int, int) int, 10) 10 | fns := []binaryCalcFunc{ 11 | func(x, y int) int { return x + y }, 12 | func(x, y int) int { return x - y }, 13 | func(x, y int) int { return x * y }, 14 | func(x, y int) int { return x / y }, 15 | func(x, y int) int { return x % y }, 16 | } 17 | 18 | c <- func(x, y int) int { 19 | return x * y 20 | } 21 | 22 | fmt.Println(fns[0](5, 6)) 23 | f := <-c 24 | fmt.Println(f(7, 10)) 25 | v, ok := i.(binaryCalcFunc) 26 | if !ok { 27 | fmt.Println("type assertion error") 28 | return 29 | } 30 | 31 | fmt.Println(v(17, 7)) 32 | } 33 | -------------------------------------------------------------------------------- /chapter4/sources/function_as_first_class_citizen_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func greeting(w http.ResponseWriter, r *http.Request) { 9 | fmt.Fprintf(w, "Welcome, Gopher!\n") 10 | } 11 | 12 | func main() { 13 | //http.ListenAndServe(":8080", http.HandlerFunc(greeting)) 14 | http.ListenAndServe(":8080", greeting) 15 | } 16 | -------------------------------------------------------------------------------- /chapter4/sources/function_as_first_class_citizen_3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type BinaryAdder interface { 6 | Add(int, int) int 7 | } 8 | 9 | type MyAdderFunc func(int, int) int 10 | 11 | func (f MyAdderFunc) Add(x, y int) int { 12 | return f(x, y) 13 | } 14 | 15 | func MyAdd(x, y int) int { 16 | return x + y 17 | } 18 | 19 | func main() { 20 | var i BinaryAdder = MyAdderFunc(MyAdd) 21 | fmt.Println(i.Add(5, 6)) 22 | } 23 | -------------------------------------------------------------------------------- /chapter4/sources/function_as_first_class_citizen_4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func times(x, y int) int { 6 | return x * y 7 | } 8 | 9 | func partialTimes(x int) func(int) int { 10 | return func(y int) int { 11 | return times(x, y) 12 | } 13 | } 14 | 15 | func main() { 16 | timesTwo := partialTimes(2) 17 | timesThree := partialTimes(3) 18 | timesFour := partialTimes(4) 19 | fmt.Println(timesTwo(5)) 20 | fmt.Println(timesThree(5)) 21 | fmt.Println(timesFour(5)) 22 | } 23 | -------------------------------------------------------------------------------- /chapter4/sources/function_as_first_class_citizen_6.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func factorial(n int) int { 6 | if n == 1 { 7 | return 1 8 | } else { 9 | return n * factorial(n-1) 10 | } 11 | } 12 | 13 | func main() { 14 | fmt.Printf("%d\n", factorial(5)) 15 | } 16 | -------------------------------------------------------------------------------- /chapter4/sources/function_as_first_class_citizen_7.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Max(n int, m int) int { 6 | if n > m { 7 | return n 8 | } else { 9 | return m 10 | } 11 | } 12 | 13 | func main() { 14 | fmt.Printf("%d\n", Max(5, 6)) 15 | } 16 | -------------------------------------------------------------------------------- /chapter4/sources/function_as_first_class_citizen_8.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Max(n int, m int, f func(y int)) { 6 | if n > m { 7 | f(n) 8 | } else { 9 | f(m) 10 | } 11 | 12 | } 13 | 14 | func main() { 15 | Max(5, 6, func(y int) { fmt.Printf("%d\n", y) }) 16 | } 17 | -------------------------------------------------------------------------------- /chapter4/sources/function_as_first_class_citizen_9.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func factorial(n int, f func(int)) { 6 | if n == 1 { 7 | f(1) //基本情况 8 | } else { 9 | factorial(n-1, func(y int) { f(n * y) }) 10 | } 11 | } 12 | 13 | func main() { 14 | factorial(5, func(y int) { fmt.Printf("%d\n", y) }) 15 | } 16 | -------------------------------------------------------------------------------- /chapter4/sources/get_image_size.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | _ "image/gif" 7 | _ "image/jpeg" 8 | _ "image/png" 9 | "os" 10 | ) 11 | 12 | func main() { 13 | // 支持png, jpeg, gif 14 | width, height, err := imageSize(os.Args[1]) 15 | if err != nil { 16 | fmt.Println("get image size error:", err) 17 | return 18 | } 19 | fmt.Printf("image size: [%d, %d]\n", width, height) 20 | } 21 | 22 | func imageSize(imageFile string) (int, int, error) { 23 | f, _ := os.Open(imageFile) 24 | defer f.Close() 25 | 26 | img, _, err := image.Decode(f) 27 | if err != nil { 28 | return 0, 0, err 29 | } 30 | 31 | b := img.Bounds() 32 | return b.Max.X, b.Max.Y, nil 33 | } 34 | -------------------------------------------------------------------------------- /chapter4/sources/method_nature_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type T struct { 4 | a int 5 | } 6 | 7 | func (t T) M1() { 8 | t.a = 10 9 | } 10 | 11 | func (t *T) M2() { 12 | t.a = 11 13 | } 14 | 15 | func main() { 16 | var t T // t.a = 0 17 | println(t.a) 18 | 19 | t.M1() 20 | println(t.a) 21 | 22 | t.M2() 23 | println(t.a) 24 | } 25 | -------------------------------------------------------------------------------- /chapter4/sources/method_nature_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type T struct { 4 | a int 5 | } 6 | 7 | func (t T) M1() { 8 | } 9 | 10 | func (t *T) M2() { 11 | t.a = 11 12 | } 13 | 14 | func main() { 15 | var t T 16 | t.M1() 17 | t.M2() // <=> (&t).M2() 18 | 19 | var pt = &T{} 20 | pt.M1() // <=> (*pt).M1() 21 | pt.M2() 22 | } 23 | -------------------------------------------------------------------------------- /chapter4/sources/method_nature_3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type field struct { 9 | name string 10 | } 11 | 12 | func (p *field) print() { 13 | fmt.Println(p.name) 14 | } 15 | 16 | func main() { 17 | data1 := []*field{{"one"}, {"two"}, {"three"}} 18 | for _, v := range data1 { 19 | go v.print() 20 | } 21 | 22 | data2 := []field{{"four"}, {"five"}, {"six"}} 23 | for _, v := range data2 { 24 | go v.print() 25 | } 26 | 27 | time.Sleep(3 * time.Second) 28 | } 29 | -------------------------------------------------------------------------------- /chapter4/sources/method_nature_4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type field struct { 9 | name string 10 | } 11 | 12 | func (p *field) print() { 13 | fmt.Println(p.name) 14 | } 15 | 16 | func main() { 17 | data1 := []*field{{"one"}, {"two"}, {"three"}} 18 | for _, v := range data1 { 19 | go (*field).print(v) 20 | } 21 | 22 | data2 := []field{{"four"}, {"five"}, {"six"}} 23 | for _, v := range data2 { 24 | go (*field).print(&v) 25 | } 26 | 27 | time.Sleep(3 * time.Second) 28 | } 29 | -------------------------------------------------------------------------------- /chapter4/sources/method_nature_5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type field struct { 9 | name string 10 | } 11 | 12 | func (p field) print() { 13 | fmt.Println(p.name) 14 | } 15 | 16 | func main() { 17 | data1 := []*field{{"one"}, {"two"}, {"three"}} 18 | for _, v := range data1 { 19 | go v.print() 20 | } 21 | 22 | data2 := []field{{"four"}, {"five"}, {"six"}} 23 | for _, v := range data2 { 24 | go v.print() 25 | } 26 | 27 | time.Sleep(3 * time.Second) 28 | } 29 | -------------------------------------------------------------------------------- /chapter4/sources/method_nature_6.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type field struct { 9 | name string 10 | } 11 | 12 | func (p field) print() { 13 | fmt.Println(p.name) 14 | } 15 | 16 | func main() { 17 | data1 := []*field{{"one"}, {"two"}, {"three"}} 18 | for _, v := range data1 { 19 | go field.print(*v) 20 | } 21 | 22 | data2 := []field{{"four"}, {"five"}, {"six"}} 23 | for _, v := range data2 { 24 | go field.print(v) 25 | } 26 | 27 | time.Sleep(3 * time.Second) 28 | } 29 | -------------------------------------------------------------------------------- /chapter4/sources/method_set_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Interface interface { 4 | M1() 5 | M2() 6 | } 7 | 8 | type T struct{} 9 | 10 | func (t T) M1() {} 11 | func (t *T) M2() {} 12 | 13 | func main() { 14 | var t T 15 | var pt *T 16 | var i Interface 17 | 18 | i = t 19 | i = pt 20 | } 21 | -------------------------------------------------------------------------------- /chapter4/sources/method_set_11.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type T struct{} 4 | 5 | func (T) M1() {} 6 | func (*T) M2() {} 7 | 8 | type Interface interface { 9 | M1() 10 | M2() 11 | } 12 | 13 | type T1 T 14 | type Interface1 Interface 15 | 16 | func main() { 17 | var t T 18 | var pt *T 19 | var t1 T1 20 | var pt1 *T1 21 | 22 | DumpMethodSet(&t) 23 | DumpMethodSet(&t1) 24 | 25 | DumpMethodSet(&pt) 26 | DumpMethodSet(&pt1) 27 | 28 | DumpMethodSet((*Interface)(nil)) 29 | DumpMethodSet((*Interface1)(nil)) 30 | } 31 | -------------------------------------------------------------------------------- /chapter4/sources/method_set_12.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type T struct{} 4 | 5 | func (T) M1() {} 6 | func (*T) M2() {} 7 | 8 | type Interface interface { 9 | M1() 10 | M2() 11 | } 12 | 13 | type T1 = T 14 | type Interface1 = Interface 15 | 16 | func main() { 17 | var t T 18 | var pt *T 19 | var t1 T1 20 | var pt1 *T1 21 | 22 | DumpMethodSet(&t) 23 | DumpMethodSet(&t1) 24 | 25 | DumpMethodSet(&pt) 26 | DumpMethodSet(&pt1) 27 | 28 | DumpMethodSet((*Interface)(nil)) 29 | DumpMethodSet((*Interface1)(nil)) 30 | } 31 | -------------------------------------------------------------------------------- /chapter4/sources/method_set_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Interface interface { 4 | M1() 5 | M2() 6 | } 7 | 8 | type T struct{} 9 | 10 | func (t T) M1() {} 11 | func (t *T) M2() {} 12 | 13 | func main() { 14 | var t T 15 | var pt *T 16 | DumpMethodSet(&t) 17 | DumpMethodSet(&pt) 18 | DumpMethodSet((*Interface)(nil)) 19 | } 20 | -------------------------------------------------------------------------------- /chapter4/sources/method_set_3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "io" 4 | 5 | func main() { 6 | DumpMethodSet((*io.Writer)(nil)) 7 | DumpMethodSet((*io.Reader)(nil)) 8 | DumpMethodSet((*io.Closer)(nil)) 9 | DumpMethodSet((*io.ReadWriter)(nil)) 10 | DumpMethodSet((*io.ReadWriteCloser)(nil)) 11 | } 12 | -------------------------------------------------------------------------------- /chapter4/sources/method_set_4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Interface1 interface { 4 | M1() 5 | } 6 | 7 | type Interface2 interface { 8 | M1() 9 | M2() 10 | } 11 | 12 | type Interface3 interface { 13 | Interface1 14 | Interface2 15 | } 16 | 17 | type Interface4 interface { 18 | Interface2 19 | M2() 20 | } 21 | 22 | func main() { 23 | DumpMethodSet((*Interface3)(nil)) 24 | } 25 | -------------------------------------------------------------------------------- /chapter4/sources/method_set_5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Interface interface { 4 | M1() 5 | M2() 6 | } 7 | 8 | type T struct { 9 | Interface 10 | } 11 | 12 | func (T) M3() {} 13 | 14 | func main() { 15 | DumpMethodSet((*Interface)(nil)) 16 | var t T 17 | var pt *T 18 | DumpMethodSet(&t) 19 | DumpMethodSet(&pt) 20 | } 21 | -------------------------------------------------------------------------------- /chapter4/sources/method_set_6.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Interface interface { 4 | M1() 5 | M2() 6 | } 7 | 8 | type T struct { 9 | Interface 10 | } 11 | 12 | func (T) M1() { 13 | println("T's M1") 14 | } 15 | 16 | type S struct{} 17 | 18 | func (S) M1() { 19 | println("S's M1") 20 | } 21 | func (S) M2() { 22 | println("S's M2") 23 | } 24 | 25 | func main() { 26 | var t = T{ 27 | Interface: S{}, 28 | } 29 | 30 | t.M1() 31 | t.M2() 32 | } 33 | -------------------------------------------------------------------------------- /chapter4/sources/method_set_7.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Interface interface { 4 | M1() 5 | M2() 6 | M3() 7 | } 8 | 9 | type Interface1 interface { 10 | M1() 11 | M2() 12 | M4() 13 | } 14 | 15 | type T struct { 16 | Interface 17 | Interface1 18 | } 19 | 20 | func main() { 21 | t := T{} 22 | t.M1() 23 | t.M2() 24 | } 25 | -------------------------------------------------------------------------------- /chapter4/sources/method_set_8.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Interface interface { 4 | M1() 5 | M2() 6 | M3() 7 | } 8 | 9 | type Interface1 interface { 10 | M1() 11 | M2() 12 | M4() 13 | } 14 | 15 | type T struct { 16 | Interface 17 | Interface1 18 | } 19 | 20 | func (T) M1() { println("T's M1") } 21 | func (T) M2() { println("T's M2") } 22 | 23 | func main() { 24 | t := T{} 25 | t.M1() 26 | t.M2() 27 | } 28 | -------------------------------------------------------------------------------- /chapter4/sources/method_set_9.go: -------------------------------------------------------------------------------- 1 | package employee 2 | 3 | type Result struct { 4 | Count int 5 | } 6 | 7 | func (r Result) Int() int { return r.Count } 8 | 9 | type Rows []struct{} 10 | 11 | type Stmt interface { 12 | Close() error 13 | NumInput() int 14 | Exec(stmt string, args ...string) (Result, error) 15 | Query(args []string) (Rows, error) 16 | } 17 | 18 | // 返回男性员工总数 19 | func MaleCount(s Stmt) (int, error) { 20 | result, err := s.Exec("select count(*) from employee_tab where gender=?", "1") 21 | if err != nil { 22 | return 0, err 23 | } 24 | 25 | return result.Int(), nil 26 | } 27 | -------------------------------------------------------------------------------- /chapter4/sources/method_set_9_test.go: -------------------------------------------------------------------------------- 1 | package employee 2 | 3 | import "testing" 4 | 5 | type fakeStmtForMaleCount struct { 6 | Stmt 7 | } 8 | 9 | func (fakeStmtForMaleCount) Exec(stmt string, args ...string) (Result, error) { 10 | return Result{Count: 5}, nil 11 | } 12 | 13 | func TestEmployeeMaleCount(t *testing.T) { 14 | f := fakeStmtForMaleCount{} 15 | c, _ := MaleCount(f) 16 | if c != 5 { 17 | t.Errorf("want: %d, actual: %d", 5, c) 18 | return 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /chapter4/sources/package-init-order/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/package-init-order 2 | 3 | go 1.13 4 | -------------------------------------------------------------------------------- /chapter4/sources/package-init-order/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | _ "github.com/bigwhite/package-init-order/pkg1" 7 | _ "github.com/bigwhite/package-init-order/pkg3" 8 | ) 9 | 10 | var ( 11 | _ = constInitCheck() 12 | v1 = variableInit("v1") 13 | v2 = variableInit("v2") 14 | ) 15 | 16 | const ( 17 | c1 = "c1" 18 | c2 = "c2" 19 | ) 20 | 21 | func constInitCheck() string { 22 | if c1 != "" { 23 | fmt.Println("main: const c1 init") 24 | } 25 | if c2 != "" { 26 | fmt.Println("main: const c2 init") 27 | } 28 | return "" 29 | } 30 | 31 | func variableInit(name string) string { 32 | fmt.Printf("main: var %s init\n", name) 33 | return name 34 | } 35 | 36 | func init() { 37 | fmt.Println("main: init") 38 | } 39 | 40 | func main() { 41 | // do nothing 42 | } 43 | -------------------------------------------------------------------------------- /chapter4/sources/package-init-order/pkg1/pkg1.go: -------------------------------------------------------------------------------- 1 | package pkg1 2 | 3 | import ( 4 | "fmt" 5 | 6 | _ "github.com/bigwhite/package-init-order/pkg2" 7 | ) 8 | 9 | var ( 10 | _ = constInitCheck() 11 | v = variableInit("v") 12 | ) 13 | 14 | const ( 15 | c = "c" 16 | ) 17 | 18 | func constInitCheck() string { 19 | if c != "" { 20 | fmt.Println("pkg1: const c init") 21 | } 22 | return "" 23 | } 24 | 25 | func variableInit(name string) string { 26 | fmt.Printf("pkg1: var %s init\n", name) 27 | return name 28 | } 29 | 30 | func init() { 31 | fmt.Println("pkg1: init") 32 | } 33 | -------------------------------------------------------------------------------- /chapter4/sources/package-init-order/pkg2/pkg2.go: -------------------------------------------------------------------------------- 1 | package pkg2 2 | 3 | import "fmt" 4 | 5 | var ( 6 | _ = constInitCheck() 7 | v = variableInit("v") 8 | ) 9 | 10 | const ( 11 | c = "c" 12 | ) 13 | 14 | func constInitCheck() string { 15 | if c != "" { 16 | fmt.Println("pkg2: const c init") 17 | } 18 | return "" 19 | } 20 | 21 | func variableInit(name string) string { 22 | fmt.Printf("pkg2: var %s init\n", name) 23 | return name 24 | } 25 | 26 | func init() { 27 | fmt.Println("pkg2: init") 28 | } 29 | -------------------------------------------------------------------------------- /chapter4/sources/package-init-order/pkg3/pkg3.go: -------------------------------------------------------------------------------- 1 | package pkg3 2 | 3 | import "fmt" 4 | 5 | var ( 6 | _ = constInitCheck() 7 | v = variableInit("v") 8 | ) 9 | 10 | const ( 11 | c = "c" 12 | ) 13 | 14 | func constInitCheck() string { 15 | if c != "" { 16 | fmt.Println("pkg3: const c init") 17 | } 18 | return "" 19 | } 20 | 21 | func variableInit(name string) string { 22 | fmt.Printf("pkg3: var %s init\n", name) 23 | return name 24 | } 25 | 26 | func init() { 27 | fmt.Println("pkg3: init") 28 | } 29 | -------------------------------------------------------------------------------- /chapter4/sources/variadic_function_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func sum(args ...int) int { 4 | var total int 5 | 6 | for _, v := range args { 7 | total += v 8 | } 9 | 10 | return total 11 | } 12 | 13 | func main() { 14 | a, b, c := 1, 2, 3 15 | println(sum(a, b, c)) 16 | nums := []int{4, 5, 6} 17 | println(sum(nums...)) 18 | } 19 | -------------------------------------------------------------------------------- /chapter4/sources/variadic_function_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func dump(args ...interface{}) { 6 | for _, v := range args { 7 | fmt.Println(v) 8 | } 9 | } 10 | 11 | func main() { 12 | //s := []string{"Tony", "John", "Jim"} 13 | s := []interface{}{"Tony", "John", "Jim"} 14 | dump(s...) 15 | } 16 | -------------------------------------------------------------------------------- /chapter4/sources/variadic_function_3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func foo(b ...byte) { 6 | fmt.Println(string(b)) 7 | } 8 | 9 | func main() { 10 | b := []byte{} 11 | b = append(b, "hello"...) 12 | fmt.Println(string(b)) 13 | 14 | foo("hello"...) 15 | } 16 | -------------------------------------------------------------------------------- /chapter4/sources/variadic_function_4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func concat(a, b int) string { 9 | return fmt.Printf("%d %d", a, b) 10 | } 11 | 12 | func concat(x, y string) string { 13 | return x + " " + y 14 | } 15 | 16 | func concat(s []string) string { 17 | return strings.Join(s, " ") 18 | } 19 | 20 | func main() { 21 | println(concat(1, 2)) 22 | println(concat("hello", "gopher")) 23 | println(concat([]string{"hello", "gopher", "!"})) 24 | } 25 | -------------------------------------------------------------------------------- /chapter5/sources/horizontal-composition-1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | r := strings.NewReader("hello, gopher!\n") 12 | lr := io.LimitReader(r, 4) 13 | if _, err := io.Copy(os.Stdout, lr); err != nil { 14 | log.Fatal(err) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /chapter5/sources/horizontal-composition-2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "log" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | func CapReader(r io.Reader) io.Reader { 12 | return &capitalizedReader{r: r} 13 | } 14 | 15 | type capitalizedReader struct { 16 | r io.Reader 17 | } 18 | 19 | func (r *capitalizedReader) Read(p []byte) (int, error) { 20 | n, err := r.r.Read(p) 21 | if err != nil { 22 | return 0, err 23 | } 24 | 25 | q := bytes.ToUpper(p) 26 | for i, v := range q { 27 | p[i] = v 28 | } 29 | return n, err 30 | } 31 | 32 | func main() { 33 | r := strings.NewReader("hello, gopher!\n") 34 | r1 := CapReader(io.LimitReader(r, 4)) 35 | if _, err := io.Copy(os.Stdout, r1); err != nil { 36 | log.Fatal(err) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /chapter5/sources/horizontal-composition-3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func greetings(w http.ResponseWriter, r *http.Request) { 9 | fmt.Fprintf(w, "Welcome!") 10 | } 11 | 12 | func main() { 13 | http.ListenAndServe(":8080", http.HandlerFunc(greetings)) 14 | } 15 | -------------------------------------------------------------------------------- /chapter5/sources/interface-internal-1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | type MyError struct { 9 | error 10 | } 11 | 12 | var ErrBad = MyError{ 13 | error: errors.New("bad error"), 14 | } 15 | 16 | func bad() bool { 17 | return false 18 | } 19 | 20 | func returnsError() error { 21 | var p *MyError = nil 22 | if bad() { 23 | p = &ErrBad 24 | } 25 | return p 26 | } 27 | 28 | func main() { 29 | e := returnsError() 30 | if e != nil { 31 | fmt.Printf("error: %+v\n", e) 32 | return 33 | } 34 | fmt.Println("ok") 35 | } 36 | -------------------------------------------------------------------------------- /chapter5/sources/interface-internal-3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "unsafe" 4 | 5 | type T int 6 | 7 | func (t T) Error() string { 8 | return "bad error" 9 | } 10 | 11 | func main() { 12 | var eif interface{} = T(5) 13 | var err error = T(5) 14 | println("eif:", eif) 15 | println("err:", err) 16 | println("eif = err:", eif == err) 17 | 18 | dumpEface(eif) 19 | dumpItabOfIface(unsafe.Pointer(&err)) 20 | dumpDataOfIface(err) 21 | } 22 | -------------------------------------------------------------------------------- /chapter5/sources/interface-internal-4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type T struct { 6 | n int 7 | s string 8 | } 9 | 10 | func (T) M1() {} 11 | func (T) M2() {} 12 | 13 | type NonEmptyInterface interface { 14 | M1() 15 | M2() 16 | } 17 | 18 | func main() { 19 | var t = T{ 20 | n: 17, 21 | s: "hello, interface", 22 | } 23 | var ei interface{} 24 | ei = t 25 | 26 | var i NonEmptyInterface 27 | i = t 28 | fmt.Println(ei) 29 | fmt.Println(i) 30 | } 31 | -------------------------------------------------------------------------------- /chapter5/sources/interface-internal-4.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter5/sources/interface-internal-4.o -------------------------------------------------------------------------------- /chapter5/sources/interface-internal-5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var n int = 61 7 | var ei interface{} = n 8 | n = 62 9 | fmt.Println("data in box:", ei) 10 | 11 | var m int = 51 12 | ei = &m 13 | m = 52 14 | 15 | p := ei.(*int) 16 | fmt.Println("data in box:", *p) 17 | } 18 | -------------------------------------------------------------------------------- /chapter5/sources/java_stringer/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | javac foo.java bar.java StringerInterface.java 3 | mv *.class stringer 4 | -------------------------------------------------------------------------------- /chapter5/sources/java_stringer/README.md: -------------------------------------------------------------------------------- 1 | java stringer/StringerInterface 2 | -------------------------------------------------------------------------------- /chapter5/sources/java_stringer/StringerInterface.java: -------------------------------------------------------------------------------- 1 | package stringer; 2 | 3 | interface Stringer { 4 | String String(); 5 | } 6 | 7 | 8 | public class StringerInterface { 9 | public static String concat(Stringer a, Stringer b) { 10 | return a.String()+b.String(); 11 | } 12 | 13 | public static void main(String args[]){ 14 | bar b = new bar(); 15 | b.s = "hello"; 16 | foo f = new foo(); 17 | f.i = 5; 18 | System.out.println(concat(b, f)); 19 | } 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /chapter5/sources/java_stringer/bar.java: -------------------------------------------------------------------------------- 1 | package stringer; 2 | 3 | public class bar implements Stringer { 4 | String s; 5 | public String String() { 6 | return s; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /chapter5/sources/java_stringer/foo.java: -------------------------------------------------------------------------------- 1 | package stringer; 2 | 3 | public class foo implements Stringer { 4 | int i; 5 | public String String() { 6 | return Integer.toString(i); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /chapter5/sources/java_stringer/stringer/Stringer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter5/sources/java_stringer/stringer/Stringer.class -------------------------------------------------------------------------------- /chapter5/sources/java_stringer/stringer/StringerInterface.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter5/sources/java_stringer/stringer/StringerInterface.class -------------------------------------------------------------------------------- /chapter5/sources/java_stringer/stringer/bar.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter5/sources/java_stringer/stringer/bar.class -------------------------------------------------------------------------------- /chapter5/sources/java_stringer/stringer/foo.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter5/sources/java_stringer/stringer/foo.class -------------------------------------------------------------------------------- /chapter5/sources/ruby_stringer/stringer_interface.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # -*- coding: UTF-8 -*- 3 | 4 | def concat(a, b) 5 | unless a.respond_to?(:string) && b.respond_to?(:string) 6 | raise ArgumentError, "无效参数" 7 | end 8 | a.string() + b.string() 9 | end 10 | 11 | class Stringer 12 | def string 13 | raise NotImplementedError 14 | end 15 | end 16 | 17 | class Foo 18 | def initialize(i) 19 | @i=i 20 | end 21 | def string 22 | @i.to_s 23 | end 24 | end 25 | 26 | class Bar 27 | def initialize(s) 28 | @s=s 29 | end 30 | def string 31 | @s 32 | end 33 | end 34 | 35 | f = Foo.new(5) 36 | b = Bar.new("hello") 37 | puts concat(b, f) 38 | -------------------------------------------------------------------------------- /chapter5/sources/send_mail_with_disclaimer/v1/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/mail 2 | 3 | go 1.13 4 | 5 | require github.com/jordan-wright/email v0.0.0-20190819015918-041e0cec78b0 6 | -------------------------------------------------------------------------------- /chapter5/sources/send_mail_with_disclaimer/v1/go.sum: -------------------------------------------------------------------------------- 1 | github.com/jordan-wright/email v0.0.0-20190819015918-041e0cec78b0 h1:9RqhD4eIjDTQuWBItAeHJfGA0QIvqsyZtr6FlgagMR4= 2 | github.com/jordan-wright/email v0.0.0-20190819015918-041e0cec78b0/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A= 3 | -------------------------------------------------------------------------------- /chapter5/sources/send_mail_with_disclaimer/v1/mail_test.go: -------------------------------------------------------------------------------- 1 | package mail_test 2 | 3 | import ( 4 | "net/smtp" 5 | "testing" 6 | 7 | mail "github.com/bigwhite/mail" 8 | ) 9 | 10 | func TestSendMail(t *testing.T) { 11 | err := mail.SendMailWithDisclaimer("gopher mail test v1", 12 | "YOUR_MAILBOX", 13 | []string{"DEST_MAILBOX"}, 14 | "hello, gopher", 15 | "smtp.163.com:25", 16 | smtp.PlainAuth("", "YOUR_EMAIL_ACCOUNT", "YOUR_EMAIL_PASSWD!", "smtp.163.com")) 17 | if err != nil { 18 | t.Fatalf("want: nil, actual: %s\n", err) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /chapter5/sources/send_mail_with_disclaimer/v2/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/mail 2 | 3 | go 1.13 4 | 5 | require github.com/jordan-wright/email v0.0.0-20190819015918-041e0cec78b0 6 | -------------------------------------------------------------------------------- /chapter5/sources/send_mail_with_disclaimer/v2/go.sum: -------------------------------------------------------------------------------- 1 | github.com/jordan-wright/email v0.0.0-20190819015918-041e0cec78b0 h1:9RqhD4eIjDTQuWBItAeHJfGA0QIvqsyZtr6FlgagMR4= 2 | github.com/jordan-wright/email v0.0.0-20190819015918-041e0cec78b0/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A= 3 | -------------------------------------------------------------------------------- /chapter6/sources/go-channel-case-1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var c = make(chan int) 4 | var a string 5 | 6 | func f() { 7 | a = "hello, world" 8 | <-c 9 | } 10 | 11 | func main() { 12 | go f() 13 | c <- 5 14 | println(a) 15 | } 16 | -------------------------------------------------------------------------------- /chapter6/sources/go-channel-case-10.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | import "time" 5 | 6 | func main() { 7 | c1, c2 := make(chan int), make(chan int) 8 | go func() { 9 | time.Sleep(time.Second * 5) 10 | c1 <- 5 11 | close(c1) 12 | }() 13 | 14 | go func() { 15 | time.Sleep(time.Second * 7) 16 | c2 <- 7 17 | close(c2) 18 | }() 19 | 20 | for { 21 | select { 22 | case x, ok := <-c1: 23 | if !ok { 24 | c1 = nil 25 | } else { 26 | fmt.Println(x) 27 | } 28 | case x, ok := <-c2: 29 | if !ok { 30 | c2 = nil 31 | } else { 32 | fmt.Println(x) 33 | } 34 | } 35 | if c1 == nil && c2 == nil { 36 | break 37 | } 38 | } 39 | fmt.Println("program end") 40 | } 41 | -------------------------------------------------------------------------------- /chapter6/sources/go-channel-case-2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type signal struct{} 9 | 10 | func worker() { 11 | println("worker is working...") 12 | time.Sleep(1 * time.Second) 13 | } 14 | 15 | func spawn(f func()) <-chan signal { 16 | c := make(chan signal) 17 | go func() { 18 | println("worker start to work...") 19 | f() 20 | c <- signal(struct{}{}) 21 | }() 22 | return c 23 | } 24 | 25 | func main() { 26 | println("start a worker...") 27 | c := spawn(worker) 28 | <-c 29 | fmt.Println("worker work done!") 30 | } 31 | -------------------------------------------------------------------------------- /chapter6/sources/go-channel-case-5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | type counter struct { 10 | sync.Mutex 11 | i int 12 | } 13 | 14 | var cter counter 15 | 16 | func Increase() int { 17 | cter.Lock() 18 | defer cter.Unlock() 19 | cter.i++ 20 | return cter.i 21 | } 22 | 23 | func main() { 24 | for i := 0; i < 10; i++ { 25 | go func(i int) { 26 | v := Increase() 27 | fmt.Printf("goroutine-%d: current counter value is %d\n", i, v) 28 | }(i) 29 | } 30 | 31 | time.Sleep(5 * time.Second) 32 | } 33 | -------------------------------------------------------------------------------- /chapter6/sources/go-channel-case-6.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type counter struct { 9 | c chan int 10 | i int 11 | } 12 | 13 | var cter counter 14 | 15 | func InitCounter() { 16 | cter = counter{ 17 | c: make(chan int), 18 | } 19 | 20 | go func() { 21 | for { 22 | cter.i++ 23 | cter.c <- cter.i 24 | } 25 | }() 26 | fmt.Println("counter init ok") 27 | } 28 | 29 | func Increase() int { 30 | return <-cter.c 31 | } 32 | 33 | func init() { 34 | InitCounter() 35 | } 36 | 37 | func main() { 38 | for i := 0; i < 10; i++ { 39 | go func(i int) { 40 | v := Increase() 41 | fmt.Printf("goroutine-%d: current counter value is %d\n", i, v) 42 | }(i) 43 | } 44 | 45 | time.Sleep(5 * time.Second) 46 | } 47 | -------------------------------------------------------------------------------- /chapter6/sources/go-channel-case-7.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | var active = make(chan struct{}, 3) 10 | var jobs = make(chan int, 10) 11 | 12 | func main() { 13 | go func() { 14 | for i := 0; i < 8; i++ { 15 | jobs <- (i + 1) 16 | } 17 | close(jobs) 18 | }() 19 | 20 | var wg sync.WaitGroup 21 | 22 | for j := range jobs { 23 | wg.Add(1) 24 | go func(j int) { 25 | active <- struct{}{} 26 | log.Printf("handle job: %d\n", j) 27 | time.Sleep(2 * time.Second) 28 | <-active 29 | wg.Done() 30 | }(j) 31 | } 32 | wg.Wait() 33 | } 34 | -------------------------------------------------------------------------------- /chapter6/sources/go-channel-case-9.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | c1, c2 := make(chan int), make(chan int) 10 | go func() { 11 | time.Sleep(time.Second * 5) 12 | c1 <- 5 13 | close(c1) 14 | }() 15 | 16 | go func() { 17 | time.Sleep(time.Second * 7) 18 | c2 <- 7 19 | close(c2) 20 | }() 21 | 22 | var ok1, ok2 bool 23 | for { 24 | select { 25 | case x := <-c1: 26 | ok1 = true 27 | fmt.Println(x) 28 | case x := <-c2: 29 | ok2 = true 30 | fmt.Println(x) 31 | } 32 | 33 | if ok1 && ok2 { 34 | break 35 | } 36 | } 37 | fmt.Println("program end") 38 | } 39 | -------------------------------------------------------------------------------- /chapter6/sources/go-channel-operation-benchmark/buffered-chan/one_to_one_cap_10_test.go: -------------------------------------------------------------------------------- 1 | package foo 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // for send benchmark test 8 | var c1 chan string 9 | 10 | // for recv benchmark test 11 | var c2 chan string 12 | 13 | func init() { 14 | c1 = make(chan string, 10) 15 | go func() { 16 | for { 17 | <-c1 18 | } 19 | }() 20 | 21 | c2 = make(chan string, 10) 22 | go func() { 23 | for { 24 | c2 <- "hello" 25 | } 26 | }() 27 | } 28 | 29 | func send(msg string) { 30 | c1 <- msg 31 | } 32 | func recv() { 33 | <-c2 34 | } 35 | 36 | func BenchmarkBufferedChan1To1SendCap10(b *testing.B) { 37 | for n := 0; n < b.N; n++ { 38 | send("hello") 39 | } 40 | } 41 | func BenchmarkBufferedChan1To1RecvCap10(b *testing.B) { 42 | for n := 0; n < b.N; n++ { 43 | recv() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /chapter6/sources/go-channel-operation-benchmark/unbuffered-chan/one_to_one_test.go: -------------------------------------------------------------------------------- 1 | package foo 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // for send benchmark test 8 | var c1 chan string 9 | 10 | // for recv benchmark test 11 | var c2 chan string 12 | 13 | func init() { 14 | c1 = make(chan string) 15 | go func() { 16 | for { 17 | <-c1 18 | } 19 | }() 20 | 21 | c2 = make(chan string) 22 | go func() { 23 | for { 24 | c2 <- "hello" 25 | } 26 | }() 27 | } 28 | 29 | func send(msg string) { 30 | c1 <- msg 31 | } 32 | func recv() { 33 | <-c2 34 | } 35 | 36 | func BenchmarkUnbufferedChan1To1Send(b *testing.B) { 37 | for n := 0; n < b.N; n++ { 38 | send("hello") 39 | } 40 | } 41 | func BenchmarkUnbufferedChan1To1Recv(b *testing.B) { 42 | for n := 0; n < b.N; n++ { 43 | recv() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /chapter6/sources/go-concurrency-pattern-1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "time" 4 | 5 | func worker(args ...interface{}) { 6 | if len(args) == 0 { 7 | return 8 | } 9 | interval, ok := args[0].(int) 10 | if !ok { 11 | return 12 | } 13 | 14 | time.Sleep(time.Second * (time.Duration(interval))) 15 | } 16 | 17 | func spawn(f func(args ...interface{}), args ...interface{}) chan struct{} { 18 | c := make(chan struct{}) 19 | go func() { 20 | f(args...) 21 | c <- struct{}{} 22 | }() 23 | return c 24 | } 25 | 26 | func main() { 27 | done := spawn(worker, 5) 28 | println("spawn a worker goroutine") 29 | <-done 30 | println("worker done") 31 | } 32 | -------------------------------------------------------------------------------- /chapter6/sources/go-scheduler-model-case1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func deadloop() { 9 | for { 10 | } 11 | } 12 | 13 | func main() { 14 | go deadloop() 15 | for { 16 | time.Sleep(time.Second * 1) 17 | fmt.Println("I got scheduled!") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter6/sources/go-scheduler-model-case2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "time" 7 | ) 8 | 9 | func deadloop() { 10 | for { 11 | } 12 | } 13 | 14 | func main() { 15 | runtime.GOMAXPROCS(1) 16 | go deadloop() 17 | for { 18 | time.Sleep(time.Second * 1) 19 | fmt.Println("I got scheduled!") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter6/sources/go-scheduler-model-case3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "time" 7 | ) 8 | 9 | func add(a, b int) int { 10 | return a + b 11 | } 12 | 13 | func deadloop() { 14 | for { 15 | add(3, 5) 16 | } 17 | } 18 | 19 | func main() { 20 | runtime.GOMAXPROCS(1) 21 | go deadloop() 22 | for { 23 | time.Sleep(time.Second * 1) 24 | fmt.Println("I got scheduled!") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter6/sources/go-scheduler-model-case4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "time" 7 | ) 8 | 9 | func add(a, b int) int { 10 | return a + b 11 | } 12 | 13 | func dummy() { 14 | add(3, 5) 15 | } 16 | 17 | func deadloop() { 18 | for { 19 | dummy() 20 | } 21 | } 22 | 23 | func main() { 24 | runtime.GOMAXPROCS(1) 25 | go deadloop() 26 | for { 27 | time.Sleep(time.Second * 1) 28 | fmt.Println("I got scheduled!") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /chapter6/sources/go-sync-package-1_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | var cs = 0 // 模拟临界区要保护的数据 9 | var mu sync.Mutex 10 | var c = make(chan struct{}, 1) 11 | 12 | func criticalSectionSyncByMutex() { 13 | mu.Lock() 14 | cs++ 15 | mu.Unlock() 16 | } 17 | 18 | func criticalSectionSyncByChan() { 19 | c <- struct{}{} 20 | cs++ 21 | <-c 22 | } 23 | 24 | func BenchmarkCriticalSectionSyncByMutex(b *testing.B) { 25 | for n := 0; n < b.N; n++ { 26 | criticalSectionSyncByMutex() 27 | } 28 | } 29 | 30 | func BenchmarkCriticalSectionSyncByChan(b *testing.B) { 31 | for n := 0; n < b.N; n++ { 32 | criticalSectionSyncByChan() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /chapter6/sources/go-sync-package-3_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | var cs1 = 0 // 模拟临界区要保护的数据 9 | var mu1 sync.Mutex 10 | var cs2 = 0 // 模拟临界区要保护的数据 11 | var mu2 sync.RWMutex 12 | 13 | func BenchmarkReadSyncByMutex(b *testing.B) { 14 | b.RunParallel(func(pb *testing.PB) { 15 | for pb.Next() { 16 | mu1.Lock() 17 | _ = cs1 18 | mu1.Unlock() 19 | } 20 | }) 21 | } 22 | 23 | func BenchmarkReadSyncByRWMutex(b *testing.B) { 24 | b.RunParallel(func(pb *testing.PB) { 25 | for pb.Next() { 26 | mu2.RLock() 27 | _ = cs2 28 | mu2.RUnlock() 29 | } 30 | }) 31 | } 32 | 33 | func BenchmarkWriteSyncByRWMutex(b *testing.B) { 34 | b.RunParallel(func(pb *testing.PB) { 35 | for pb.Next() { 36 | mu2.Lock() 37 | cs2++ 38 | mu2.Unlock() 39 | } 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /chapter6/sources/go-sync-package-7_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "sync" 6 | "testing" 7 | ) 8 | 9 | var bufPool = sync.Pool{ 10 | New: func() interface{} { 11 | return new(bytes.Buffer) 12 | }, 13 | } 14 | 15 | func writeBufFromPool(data string) { 16 | b := bufPool.Get().(*bytes.Buffer) 17 | b.Reset() 18 | b.WriteString(data) 19 | bufPool.Put(b) 20 | } 21 | func writeBufFromNew(data string) *bytes.Buffer { 22 | b := new(bytes.Buffer) 23 | b.WriteString(data) 24 | return b 25 | } 26 | 27 | func BenchmarkWithoutPool(b *testing.B) { 28 | b.ReportAllocs() 29 | for i := 0; i < b.N; i++ { 30 | writeBufFromNew("hello") 31 | } 32 | } 33 | 34 | func BenchmarkWithPool(b *testing.B) { 35 | b.ReportAllocs() 36 | for i := 0; i < b.N; i++ { 37 | writeBufFromPool("hello") 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /chapter7/sources/JavaDemoHeightException/Demo.java: -------------------------------------------------------------------------------- 1 | package demo; 2 | 3 | public class Demo { 4 | public static void main(String[] args) { 5 | int height = 300; 6 | try { 7 | HeightInput.checkHeight(height); 8 | } catch (HeightOutOfBound e) { 9 | System.out.printf("%s %s\n", "Are you a real human?", e); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter7/sources/JavaDemoHeightException/HeightInput.java: -------------------------------------------------------------------------------- 1 | package demo; 2 | 3 | public class HeightInput { 4 | public static void checkHeight(int height) throws HeightOutOfBound { 5 | if(height>20 && height<300){ 6 | System.out.print("ok"); 7 | }else{ 8 | throw new HeightOutOfBound(); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /chapter7/sources/JavaDemoHeightException/HeightOutOfBound.java: -------------------------------------------------------------------------------- 1 | package demo; 2 | 3 | public class HeightOutOfBound extends Exception { 4 | public String toString() { 5 | return "the height is out of the human's height bound"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /chapter7/sources/JavaDemoHeightException/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | javac Demo.java HeightInput.java HeightOutOfBound.java 3 | mv *.class demo 4 | 5 | clean: 6 | rm -f demo/*.class 7 | -------------------------------------------------------------------------------- /chapter7/sources/JavaDemoHeightException/README.md: -------------------------------------------------------------------------------- 1 | java demo/Demo 2 | -------------------------------------------------------------------------------- /chapter7/sources/JavaDemoHeightException/demo/.gitkeeper: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter7/sources/JavaDemoHeightException/demo/.gitkeeper -------------------------------------------------------------------------------- /chapter7/sources/go-error-handling-strategy-1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var ErrSentinel = errors.New("the underlying sentinel error") 9 | 10 | func main() { 11 | err1 := fmt.Errorf("wrap err1: %w", ErrSentinel) 12 | err2 := fmt.Errorf("wrap err2: %w", err1) 13 | if errors.Is(err2, ErrSentinel) { 14 | println("err is ErrSentinel") 15 | return 16 | } 17 | 18 | println("err is not ErrSentinel") 19 | } 20 | -------------------------------------------------------------------------------- /chapter7/sources/go-error-handling-strategy-2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | type MyError struct { 9 | e string 10 | } 11 | 12 | func (e *MyError) Error() string { 13 | return e.e 14 | } 15 | 16 | func main() { 17 | var err = &MyError{"my error type"} 18 | err1 := fmt.Errorf("wrap err1: %w", err) 19 | err2 := fmt.Errorf("wrap err2: %w", err1) 20 | var e *MyError 21 | if errors.As(err2, &e) { 22 | println("err is a variable of MyError type ") 23 | println(e == err) 24 | return 25 | } 26 | 27 | println("err is not a variable of the MyError type ") 28 | } 29 | -------------------------------------------------------------------------------- /chapter8/sources/benchmark-compare/new.txt: -------------------------------------------------------------------------------- 1 | goos: darwin 2 | goarch: amd64 3 | BenchmarkStrcat-8 22876281 51.4 ns/op 4 | BenchmarkStrcat-8 23847198 55.3 ns/op 5 | BenchmarkStrcat-8 22036873 52.6 ns/op 6 | BenchmarkStrcat-8 23761320 50.2 ns/op 7 | BenchmarkStrcat-8 23820279 51.5 ns/op 8 | PASS 9 | ok command-line-arguments 6.347s 10 | -------------------------------------------------------------------------------- /chapter8/sources/benchmark-compare/new_with_mem.txt: -------------------------------------------------------------------------------- 1 | goos: darwin 2 | goarch: amd64 3 | BenchmarkStrcat-8 22369525 50.1 ns/op 48 B/op 1 allocs/op 4 | BenchmarkStrcat-8 24316729 49.9 ns/op 48 B/op 1 allocs/op 5 | BenchmarkStrcat-8 24326886 51.6 ns/op 48 B/op 1 allocs/op 6 | BenchmarkStrcat-8 24309139 49.8 ns/op 48 B/op 1 allocs/op 7 | BenchmarkStrcat-8 24161436 51.4 ns/op 48 B/op 1 allocs/op 8 | PASS 9 | ok command-line-arguments 6.308s 10 | -------------------------------------------------------------------------------- /chapter8/sources/benchmark-compare/old.txt: -------------------------------------------------------------------------------- 1 | goos: darwin 2 | goarch: amd64 3 | BenchmarkStrcat-8 12611113 92.8 ns/op 4 | BenchmarkStrcat-8 13031013 91.9 ns/op 5 | BenchmarkStrcat-8 13107606 96.1 ns/op 6 | BenchmarkStrcat-8 13322605 89.4 ns/op 7 | BenchmarkStrcat-8 13095626 91.2 ns/op 8 | PASS 9 | ok command-line-arguments 6.491s 10 | -------------------------------------------------------------------------------- /chapter8/sources/benchmark-compare/old_with_mem.txt: -------------------------------------------------------------------------------- 1 | goos: darwin 2 | goarch: amd64 3 | BenchmarkStrcat-8 13133134 90.7 ns/op 80 B/op 2 allocs/op 4 | BenchmarkStrcat-8 13365381 90.2 ns/op 80 B/op 2 allocs/op 5 | BenchmarkStrcat-8 13364576 90.7 ns/op 80 B/op 2 allocs/op 6 | BenchmarkStrcat-8 13371774 89.9 ns/op 80 B/op 2 allocs/op 7 | BenchmarkStrcat-8 13382331 91.1 ns/op 80 B/op 2 allocs/op 8 | PASS 9 | ok command-line-arguments 6.498s 10 | -------------------------------------------------------------------------------- /chapter8/sources/benchmark-compare/strcat_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | var sl = []string{ 9 | "Rob Pike ", 10 | "Robert Griesemer ", 11 | "Ken Thompson ", 12 | } 13 | 14 | func Strcat(sl []string) string { 15 | return concatStringByJoin(sl) 16 | //return concatStringByOperator(sl) 17 | } 18 | 19 | func concatStringByOperator(sl []string) string { 20 | var s string 21 | for _, v := range sl { 22 | s += v 23 | } 24 | return s 25 | } 26 | 27 | func concatStringByJoin(sl []string) string { 28 | return strings.Join(sl, "") 29 | } 30 | 31 | func BenchmarkStrcat(b *testing.B) { 32 | for n := 0; n < b.N; n++ { 33 | Strcat(sl) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chapter8/sources/classic_testfixture_test.go: -------------------------------------------------------------------------------- 1 | package demo_test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func setUp(testName string) func() { 9 | fmt.Printf("\tsetUp fixture for %s\n", testName) 10 | return func() { 11 | fmt.Printf("\ttearDown fixture for %s\n", testName) 12 | } 13 | } 14 | 15 | func TestFunc1(t *testing.T) { 16 | defer setUp(t.Name())() 17 | fmt.Printf("\tExecute test: %s\n", t.Name()) 18 | } 19 | 20 | func TestFunc2(t *testing.T) { 21 | defer setUp(t.Name())() 22 | fmt.Printf("\tExecute test: %s\n", t.Name()) 23 | } 24 | 25 | func TestFunc3(t *testing.T) { 26 | defer setUp(t.Name())() 27 | fmt.Printf("\tExecute test: %s\n", t.Name()) 28 | } 29 | -------------------------------------------------------------------------------- /chapter8/sources/delve-demo1/cmd/delve-demo1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/bigwhite/delve-demo1/pkg/foo" 7 | ) 8 | 9 | func main() { 10 | a := 3 11 | b := 10 12 | c := foo.Foo(a, b) 13 | fmt.Println(c) 14 | } 15 | -------------------------------------------------------------------------------- /chapter8/sources/delve-demo1/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/delve-demo1 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /chapter8/sources/delve-demo1/pkg/foo/foo.go: -------------------------------------------------------------------------------- 1 | package foo 2 | 3 | func Foo(step, count int) int { 4 | sum := 0 5 | for i := 0; i < count; i++ { 6 | sum += step 7 | } 8 | return sum 9 | } 10 | -------------------------------------------------------------------------------- /chapter8/sources/delve-demo2/.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter8/sources/delve-demo2/.swp -------------------------------------------------------------------------------- /chapter8/sources/delve-demo2/cmd/delve-demo2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | 8 | "github.com/bigwhite/delve-demo2/pkg/bar" 9 | "github.com/bigwhite/delve-demo2/pkg/foo" 10 | ) 11 | 12 | func main() { 13 | var wg sync.WaitGroup 14 | wg.Add(1) 15 | go func() { 16 | for { 17 | d := 2 18 | e := 20 19 | f := bar.Bar(d, e) 20 | fmt.Println(f) 21 | time.Sleep(2 * time.Second) 22 | } 23 | wg.Done() 24 | }() 25 | a := 3 26 | b := 10 27 | c := foo.Foo(a, b) 28 | fmt.Println(c) 29 | wg.Wait() 30 | fmt.Println("program exit") 31 | } 32 | -------------------------------------------------------------------------------- /chapter8/sources/delve-demo2/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/delve-demo2 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /chapter8/sources/delve-demo2/pkg/bar/bar.go: -------------------------------------------------------------------------------- 1 | package bar 2 | 3 | func Bar(step, count int) int { 4 | sum := 1 5 | for i := 0; i < count; i++ { 6 | sum *= step 7 | } 8 | return sum 9 | } 10 | -------------------------------------------------------------------------------- /chapter8/sources/delve-demo2/pkg/foo/foo.go: -------------------------------------------------------------------------------- 1 | package foo 2 | 3 | func Foo(step, count int) int { 4 | sum := 0 5 | for i := 0; i < count; i++ { 6 | sum += step 7 | } 8 | return sum 9 | } 10 | -------------------------------------------------------------------------------- /chapter8/sources/delve-demo3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var p *int 7 | p = nil 8 | *p = 1 9 | fmt.Println("program exit") 10 | } 11 | -------------------------------------------------------------------------------- /chapter8/sources/expvar_demo1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "expvar" 5 | "fmt" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | http.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 11 | w.Write([]byte("hi")) 12 | })) 13 | fmt.Println(http.ListenAndServe("localhost:8080", nil)) 14 | } 15 | -------------------------------------------------------------------------------- /chapter8/sources/expvar_demo2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "expvar" 5 | "fmt" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | mux := http.NewServeMux() 11 | mux.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 12 | w.Write([]byte("hi")) 13 | })) 14 | mux.Handle("/debug/vars", expvar.Handler()) 15 | fmt.Println(http.ListenAndServe("localhost:8080", mux)) 16 | } 17 | -------------------------------------------------------------------------------- /chapter8/sources/expvar_demo3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "expvar" 5 | "fmt" 6 | "net/http" 7 | "strconv" 8 | "sync/atomic" 9 | ) 10 | 11 | type CustomVar struct { 12 | value int64 13 | } 14 | 15 | func (v *CustomVar) String() string { 16 | return strconv.FormatInt(atomic.LoadInt64(&v.value), 10) 17 | } 18 | 19 | func (v *CustomVar) Add(delta int64) { 20 | atomic.AddInt64(&v.value, delta) 21 | } 22 | 23 | func (v *CustomVar) Set(value int64) { 24 | atomic.StoreInt64(&v.value, value) 25 | } 26 | 27 | func init() { 28 | customVar := &CustomVar{ 29 | value: 17, 30 | } 31 | expvar.Publish("customVar", customVar) 32 | 33 | } 34 | 35 | func main() { 36 | http.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 37 | w.Write([]byte("hi")) 38 | })) 39 | fmt.Println(http.ListenAndServe("localhost:8080", nil)) 40 | } 41 | -------------------------------------------------------------------------------- /chapter8/sources/expvar_demo4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "expvar" 5 | "fmt" 6 | "net/http" 7 | "time" 8 | ) 9 | 10 | var customVar *expvar.Int 11 | 12 | func init() { 13 | customVar = expvar.NewInt("customVar") 14 | customVar.Set(17) 15 | } 16 | 17 | func main() { 18 | http.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 19 | w.Write([]byte("hi")) 20 | })) 21 | 22 | // 模拟业务逻辑 23 | go func() { 24 | //... ... 25 | for { 26 | customVar.Add(1) 27 | time.Sleep(time.Second) 28 | } 29 | }() 30 | 31 | fmt.Println(http.ListenAndServe("localhost:8080", nil)) 32 | } 33 | -------------------------------------------------------------------------------- /chapter8/sources/expvar_demo5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "expvar" 5 | "fmt" 6 | "net/http" 7 | "time" 8 | ) 9 | 10 | var customVar *expvar.Map 11 | 12 | func init() { 13 | customVar = expvar.NewMap("customVar") 14 | 15 | var field1 expvar.Int 16 | var field2 expvar.Float 17 | customVar.Set("field1", &field1) 18 | customVar.Set("field2", &field2) 19 | } 20 | 21 | func main() { 22 | http.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 23 | w.Write([]byte("hi")) 24 | })) 25 | 26 | // 模拟业务逻辑 27 | go func() { 28 | //... ... 29 | for { 30 | customVar.Add("field1", 1) 31 | customVar.AddFloat("field2", 0.001) 32 | time.Sleep(time.Second) 33 | } 34 | }() 35 | 36 | fmt.Println(http.ListenAndServe("localhost:8080", nil)) 37 | } 38 | -------------------------------------------------------------------------------- /chapter8/sources/faketest1/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/mailclient 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /chapter8/sources/faketest1/mailclient.go: -------------------------------------------------------------------------------- 1 | package mailclient 2 | 3 | import ( 4 | "github.com/bigwhite/mailclient/mailer" 5 | "github.com/bigwhite/mailclient/sign" 6 | ) 7 | 8 | type mailClient struct { 9 | mlr mailer.Mailer 10 | } 11 | 12 | func New(mlr mailer.Mailer) *mailClient { 13 | return &mailClient{ 14 | mlr: mlr, 15 | } 16 | } 17 | 18 | func (c *mailClient) ComposeAndSend(subject string, 19 | destinations []string, body string) (string, error) { 20 | signTxt := sign.Get() 21 | newBody := body + "\n" + signTxt 22 | 23 | for _, dest := range destinations { 24 | err := c.mlr.SendMail(subject, dest, newBody) 25 | if err != nil { 26 | return "", err 27 | } 28 | } 29 | return newBody, nil 30 | } 31 | -------------------------------------------------------------------------------- /chapter8/sources/faketest1/mailer/mailer.go: -------------------------------------------------------------------------------- 1 | package mailer 2 | 3 | type Mailer interface { 4 | SendMail(subject, destination, body string) error 5 | } 6 | -------------------------------------------------------------------------------- /chapter8/sources/faketest1/sign/sign.go: -------------------------------------------------------------------------------- 1 | package sign 2 | 3 | import "time" 4 | 5 | func Get() string { 6 | now := time.Now().Format(time.RFC1123) 7 | return now 8 | } 9 | -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/corpus/1b7c3c5fec431a18fdebaa415d1f89a8f7a325bd-4: -------------------------------------------------------------------------------- 1 | FUZ92 -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/corpus/1c10cdd1846110ecd86a3cb4c28e2c2cf101b284-2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter8/sources/fuzz-test-demo/corpus/1c10cdd1846110ecd86a3cb4c28e2c2cf101b284-2 -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/corpus/2f438287a845a438f2af2e9c27b1864cf0b3e1fa-3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter8/sources/fuzz-test-demo/corpus/2f438287a845a438f2af2e9c27b1864cf0b3e1fa-3 -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/corpus/48899690e4a8e4c04ff60ea6cdd52ec80a394b69-5: -------------------------------------------------------------------------------- 1 | FUZZ2 -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/corpus/66a37c87267bf17ae4c794158f1de4bc70ac8ab2-1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter8/sources/fuzz-test-demo/corpus/66a37c87267bf17ae4c794158f1de4bc70ac8ab2-1 -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/corpus/da39a3ee5e6b4b0d3255bfef95601890afd80709: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter8/sources/fuzz-test-demo/corpus/da39a3ee5e6b4b0d3255bfef95601890afd80709 -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/crashers/df779ced6b712c5fca247e465de2de474d1d23b9: -------------------------------------------------------------------------------- 1 | FUZZI -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/crashers/df779ced6b712c5fca247e465de2de474d1d23b9.quoted: -------------------------------------------------------------------------------- 1 | "FUZZI" 2 | -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/fuzz-test-demo 2 | 3 | go 1.14 4 | 5 | require github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813 // indirect 6 | -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/go.sum: -------------------------------------------------------------------------------- 1 | github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813 h1:NgO45/5mBLRVfiXerEFzH6ikcZ7DNRPS639xFg3ENzU= 2 | github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= 3 | -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/parse_complex.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | func ParseComplex(data [] byte) bool { 4 | if len(data) == 5 { 5 | if data[0] == 'F' && data[1] == 'U' && data[2] == 'Z' && data[3] == 'Z' && data[4] == 'I' && data[5] == 'T' { 6 | return true 7 | } 8 | } 9 | return false 10 | } -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/parse_complex_fuzz.go: -------------------------------------------------------------------------------- 1 | // +build gofuzz 2 | 3 | package parser 4 | 5 | func Fuzz(data []byte) int { 6 | ParseComplex(data) 7 | return 0 8 | } 9 | 10 | -------------------------------------------------------------------------------- /chapter8/sources/fuzz-test-demo/suppressions/4db970443bac2de13454771685ab603e779152b4: -------------------------------------------------------------------------------- 1 | panic: runtime error: index out of range [5] with length 5 2 | github.com/bigwhite/fuzz-test-demo.ParseComplex.func5 3 | github.com/bigwhite/fuzz-test-demo.ParseComplex 4 | github.com/bigwhite/fuzz-test-demo.Fuzz 5 | go-fuzz-dep.Main 6 | main.main 7 | -------------------------------------------------------------------------------- /chapter8/sources/go-pprof-optimization-demo/step0/demo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "regexp" 8 | "sync/atomic" 9 | ) 10 | 11 | var visitors int64 // must be accessed atomically 12 | 13 | func handleHi(w http.ResponseWriter, r *http.Request) { 14 | if match, _ := regexp.MatchString(`^\w*$`, r.FormValue("color")); !match { 15 | http.Error(w, "Optional color is invalid", http.StatusBadRequest) 16 | return 17 | } 18 | visitNum := atomic.AddInt64(&visitors, 1) 19 | w.Header().Set("Content-Type", "text/html; charset=utf-8") 20 | w.Write([]byte("

Welcome!

You are visitor number " + fmt.Sprint(visitNum) + "!")) 22 | } 23 | 24 | func main() { 25 | log.Printf("Starting on port 8080") 26 | http.HandleFunc("/hi", handleHi) 27 | log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil)) 28 | } 29 | -------------------------------------------------------------------------------- /chapter8/sources/go-pprof-optimization-demo/step1/cpu.prof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter8/sources/go-pprof-optimization-demo/step1/cpu.prof -------------------------------------------------------------------------------- /chapter8/sources/go-pprof-optimization-demo/step1/demo_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "net/http" 6 | "net/http/httptest" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | func BenchmarkHi(b *testing.B) { 12 | req, err := http.ReadRequest(bufio.NewReader(strings.NewReader("GET /hi HTTP/1.0\r\n\r\n"))) 13 | if err != nil { 14 | b.Fatal(err) 15 | } 16 | rw := httptest.NewRecorder() 17 | b.ResetTimer() 18 | 19 | for i := 0; i < b.N; i++ { 20 | handleHi(rw, req) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /chapter8/sources/go-pprof-optimization-demo/step2/demo_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "net/http" 6 | "net/http/httptest" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | func BenchmarkHi(b *testing.B) { 12 | b.ReportAllocs() 13 | req, err := http.ReadRequest(bufio.NewReader(strings.NewReader("GET /hi HTTP/1.0\r\n\r\n"))) 14 | if err != nil { 15 | b.Fatal(err) 16 | } 17 | rw := httptest.NewRecorder() 18 | b.ResetTimer() 19 | 20 | for i := 0; i < b.N; i++ { 21 | handleHi(rw, req) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /chapter8/sources/go-pprof-optimization-demo/step2/mem.prof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter8/sources/go-pprof-optimization-demo/step2/mem.prof -------------------------------------------------------------------------------- /chapter8/sources/go-pprof-optimization-demo/step3/demo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "regexp" 8 | "sync/atomic" 9 | ) 10 | 11 | var visitors int64 // must be accessed atomically 12 | 13 | var rxOptionalID = regexp.MustCompile(`^\d*$`) 14 | 15 | func handleHi(w http.ResponseWriter, r *http.Request) { 16 | if !rxOptionalID.MatchString(r.FormValue("color")) { 17 | http.Error(w, "Optional color is invalid", http.StatusBadRequest) 18 | return 19 | } 20 | 21 | visitNum := atomic.AddInt64(&visitors, 1) 22 | fmt.Fprintf(w, "

Welcome!

You are visitor number %d!", r.FormValue("color"), visitNum) 23 | } 24 | 25 | func main() { 26 | log.Printf("Starting on port 8080") 27 | http.HandleFunc("/hi", handleHi) 28 | log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil)) 29 | } 30 | -------------------------------------------------------------------------------- /chapter8/sources/go-pprof-optimization-demo/step3/demo_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "net/http" 6 | "net/http/httptest" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | func BenchmarkHi(b *testing.B) { 12 | b.ReportAllocs() 13 | req, err := http.ReadRequest(bufio.NewReader(strings.NewReader("GET /hi HTTP/1.0\r\n\r\n"))) 14 | if err != nil { 15 | b.Fatal(err) 16 | } 17 | rw := httptest.NewRecorder() 18 | b.ResetTimer() 19 | 20 | for i := 0; i < b.N; i++ { 21 | handleHi(rw, req) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /chapter8/sources/go-pprof-optimization-demo/step3/mem.prof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter8/sources/go-pprof-optimization-demo/step3/mem.prof -------------------------------------------------------------------------------- /chapter8/sources/go-pprof-optimization-demo/step4/demo_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "net/http" 6 | "net/http/httptest" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | func BenchmarkHi(b *testing.B) { 12 | b.ReportAllocs() 13 | req, err := http.ReadRequest(bufio.NewReader(strings.NewReader("GET /hi HTTP/1.0\r\n\r\n"))) 14 | if err != nil { 15 | b.Fatal(err) 16 | } 17 | rw := httptest.NewRecorder() 18 | b.ResetTimer() 19 | 20 | for i := 0; i < b.N; i++ { 21 | handleHi(rw, req) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /chapter8/sources/go-pprof-optimization-demo/step4/mem.prof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter8/sources/go-pprof-optimization-demo/step4/mem.prof -------------------------------------------------------------------------------- /chapter8/sources/go-pprof-optimization-demo/step5/block.prof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter8/sources/go-pprof-optimization-demo/step5/block.prof -------------------------------------------------------------------------------- /chapter8/sources/mocktest/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/mailclient 2 | 3 | go 1.14 4 | 5 | require github.com/golang/mock v1.4.3 6 | -------------------------------------------------------------------------------- /chapter8/sources/mocktest/mailclient.go: -------------------------------------------------------------------------------- 1 | package mailclient 2 | 3 | import ( 4 | "github.com/bigwhite/mailclient/mailer" 5 | "github.com/bigwhite/mailclient/sign" 6 | ) 7 | 8 | type mailClient struct { 9 | mlr mailer.Mailer 10 | } 11 | 12 | func New(mlr mailer.Mailer) *mailClient { 13 | return &mailClient{ 14 | mlr: mlr, 15 | } 16 | } 17 | 18 | var getSign = sign.Get 19 | 20 | func (c *mailClient) ComposeAndSend(subject string, sender string, destinations []string, body string) (string, error) { 21 | signTxt := getSign(sender) 22 | newBody := body + "\n" + signTxt 23 | 24 | for _, dest := range destinations { 25 | err := c.mlr.SendMail(subject, sender, dest, newBody) 26 | if err != nil { 27 | return "", err 28 | } 29 | } 30 | return newBody, nil 31 | } 32 | -------------------------------------------------------------------------------- /chapter8/sources/mocktest/mailer/mailer.go: -------------------------------------------------------------------------------- 1 | //go:generate mockgen -source=./mailer.go -destination=./mock_mailer.go -package=mailer Mailer 2 | 3 | package mailer 4 | 5 | type Mailer interface { 6 | SendMail(subject, sender, destination, body string) error 7 | } 8 | -------------------------------------------------------------------------------- /chapter8/sources/mocktest/sign/sign.go: -------------------------------------------------------------------------------- 1 | package sign 2 | 3 | import "time" 4 | 5 | func Get(sender string) string { 6 | now := time.Now().Format(time.RFC1123) 7 | return now 8 | } 9 | -------------------------------------------------------------------------------- /chapter8/sources/non_table_driven_strings_test.go: -------------------------------------------------------------------------------- 1 | package string_test 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestCompare(t *testing.T) { 9 | var a, b string 10 | var i int 11 | 12 | a, b = "", "" 13 | i = 0 14 | cmp := strings.Compare(a, b) 15 | if cmp != i { 16 | t.Errorf(`want %v, but Compare(%q, %q) = %v`, i, a, b, cmp) 17 | } 18 | 19 | a, b = "a", "" 20 | i = 1 21 | cmp = strings.Compare(a, b) 22 | if cmp != i { 23 | t.Errorf(`want %v, but Compare(%q, %q) = %v`, i, a, b, cmp) 24 | } 25 | 26 | a, b = "", "a" 27 | i = -1 28 | cmp = strings.Compare(a, b) 29 | if cmp != i { 30 | t.Errorf(`want %v, but Compare(%q, %q) = %v`, i, a, b, cmp) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter8/sources/pprof_standalone1_cpu.prof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter8/sources/pprof_standalone1_cpu.prof -------------------------------------------------------------------------------- /chapter8/sources/pprof_standalone2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | _ "net/http/pprof" 8 | "os" 9 | "os/signal" 10 | "syscall" 11 | ) 12 | 13 | func main() { 14 | http.Handle("/hello", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 15 | fmt.Println(*r) 16 | w.Write([]byte("hello")) 17 | })) 18 | s := http.Server{ 19 | Addr: "localhost:8080", 20 | } 21 | c := make(chan os.Signal, 1) 22 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) 23 | go func() { 24 | <-c 25 | s.Shutdown(context.Background()) 26 | }() 27 | fmt.Println(s.ListenAndServe()) 28 | } 29 | -------------------------------------------------------------------------------- /chapter8/sources/pprof_standalone3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | "net/http/pprof" 8 | "os" 9 | "os/signal" 10 | "syscall" 11 | ) 12 | 13 | func main() { 14 | mux := http.NewServeMux() 15 | mux.HandleFunc("/debug/pprof/", pprof.Index) 16 | mux.HandleFunc("/debug/pprof/profile", pprof.Profile) 17 | mux.HandleFunc("/hello", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 18 | fmt.Println(*r) 19 | w.Write([]byte("hello")) 20 | })) 21 | s := http.Server{ 22 | Addr: "localhost:8080", 23 | Handler: mux, 24 | } 25 | c := make(chan os.Signal, 1) 26 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) 27 | go func() { 28 | <-c 29 | s.Shutdown(context.Background()) 30 | }() 31 | fmt.Println(s.ListenAndServe()) 32 | } 33 | -------------------------------------------------------------------------------- /chapter8/sources/pprof_standalone4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | _ "net/http/pprof" 7 | "os" 8 | "os/signal" 9 | "sync" 10 | "syscall" 11 | "time" 12 | ) 13 | 14 | func main() { 15 | go func() { 16 | fmt.Println(http.ListenAndServe("localhost:8080", nil)) 17 | }() 18 | 19 | var wg sync.WaitGroup 20 | c := make(chan os.Signal, 1) 21 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) 22 | wg.Add(1) 23 | go func() { 24 | for { 25 | select { 26 | case <-c: 27 | wg.Done() 28 | return 29 | default: 30 | s1 := "hello," 31 | s2 := "gopher" 32 | s3 := "!" 33 | _ = s1 + s2 + s3 34 | } 35 | 36 | time.Sleep(100 * time.Millisecond) 37 | } 38 | }() 39 | wg.Wait() 40 | fmt.Println("program exit") 41 | } 42 | -------------------------------------------------------------------------------- /chapter8/sources/stubtest1/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/weathercli 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /chapter8/sources/stubtest2/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/mailclient 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /chapter8/sources/stubtest2/mailclient.go: -------------------------------------------------------------------------------- 1 | package mailclient 2 | 3 | import ( 4 | "github.com/bigwhite/mailclient/mailer" 5 | "github.com/bigwhite/mailclient/sign" 6 | ) 7 | 8 | type mailClient struct { 9 | mlr mailer.Mailer 10 | } 11 | 12 | func New(mlr mailer.Mailer) *mailClient { 13 | return &mailClient{ 14 | mlr: mlr, 15 | } 16 | } 17 | 18 | var getSign = sign.Get 19 | 20 | func (c *mailClient) ComposeAndSend(subject, sender string, destinations []string, body string) (string, error) { 21 | signTxt := getSign(sender) 22 | newBody := body + "\n" + signTxt 23 | 24 | for _, dest := range destinations { 25 | err := c.mlr.SendMail(subject, sender, dest, newBody) 26 | if err != nil { 27 | return "", err 28 | } 29 | } 30 | return newBody, nil 31 | } 32 | -------------------------------------------------------------------------------- /chapter8/sources/stubtest2/mailer/mailer.go: -------------------------------------------------------------------------------- 1 | package mailer 2 | 3 | type Mailer interface { 4 | SendMail(subject, sender string, destination string, body string) error 5 | } 6 | -------------------------------------------------------------------------------- /chapter8/sources/stubtest2/sign/sign.go: -------------------------------------------------------------------------------- 1 | package sign 2 | 3 | import "time" 4 | 5 | func Get(sender string) string { 6 | now := time.Now().Format(time.RFC1123) 7 | return now 8 | } 9 | -------------------------------------------------------------------------------- /chapter8/sources/stubtest3/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bigwhite/mailclient 2 | 3 | go 1.14 4 | 5 | require github.com/prashantv/gostub v1.0.0 6 | -------------------------------------------------------------------------------- /chapter8/sources/stubtest3/go.sum: -------------------------------------------------------------------------------- 1 | github.com/prashantv/gostub v1.0.0 h1:wTzvgO04xSS3gHuz6Vhuo0/kvWelyJxwNS0IRBPAwGY= 2 | github.com/prashantv/gostub v1.0.0/go.mod h1:dP1v6T1QzyGJJKFocwAU0lSZKpfjstjH8TlhkEU0on0= 3 | -------------------------------------------------------------------------------- /chapter8/sources/stubtest3/mailclient.go: -------------------------------------------------------------------------------- 1 | package mailclient 2 | 3 | import ( 4 | "github.com/bigwhite/mailclient/mailer" 5 | "github.com/bigwhite/mailclient/sign" 6 | ) 7 | 8 | type mailClient struct { 9 | mlr mailer.Mailer 10 | } 11 | 12 | func New(mlr mailer.Mailer) *mailClient { 13 | return &mailClient{ 14 | mlr: mlr, 15 | } 16 | } 17 | 18 | var getSign = sign.Get 19 | 20 | func (c *mailClient) ComposeAndSend(subject, sender string, destinations []string, body string) (string, error) { 21 | signTxt := getSign(sender) 22 | newBody := body + "\n" + signTxt 23 | 24 | for _, dest := range destinations { 25 | err := c.mlr.SendMail(subject, sender, dest, newBody) 26 | if err != nil { 27 | return "", err 28 | } 29 | } 30 | return newBody, nil 31 | } 32 | -------------------------------------------------------------------------------- /chapter8/sources/stubtest3/mailer/mailer.go: -------------------------------------------------------------------------------- 1 | package mailer 2 | 3 | type Mailer interface { 4 | SendMail(subject, sender string, destination string, body string) error 5 | } 6 | -------------------------------------------------------------------------------- /chapter8/sources/stubtest3/sign/sign.go: -------------------------------------------------------------------------------- 1 | package sign 2 | 3 | import "time" 4 | 5 | func Get(sender string) string { 6 | now := time.Now().Format(time.RFC1123) 7 | return now 8 | } 9 | -------------------------------------------------------------------------------- /chapter8/sources/table_driven_strings_by_name_test.go: -------------------------------------------------------------------------------- 1 | package string_test 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestCompare(t *testing.T) { 9 | compareTests := []struct { 10 | name, a, b string 11 | i int 12 | }{ 13 | {"compareTwoEmptyString", "", "", 7}, 14 | {"compareSecondStringEmpty", "a", "", 6}, 15 | {"compareFirstStringEmpty", "", "a", -1}, 16 | } 17 | 18 | for _, tt := range compareTests { 19 | cmp := strings.Compare(tt.a, tt.b) 20 | if cmp != tt.i { 21 | t.Errorf(`[%s] want %v, but Compare(%q, %q) = %v`, tt.name, tt.i, tt.a, tt.b, cmp) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter8/sources/table_driven_strings_by_offset_test.go: -------------------------------------------------------------------------------- 1 | package string_test 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestCompare(t *testing.T) { 9 | compareTests := []struct { 10 | a, b string 11 | i int 12 | }{ 13 | {"", "", 7}, 14 | {"a", "", 6}, 15 | {"", "a", -1}, 16 | } 17 | 18 | for i, tt := range compareTests { 19 | cmp := strings.Compare(tt.a, tt.b) 20 | if cmp != tt.i { 21 | t.Errorf(`[table offset: %v] want %v, but Compare(%q, %q) = %v`, i+1, tt.i, tt.a, tt.b, cmp) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter8/sources/table_driven_strings_more_cases_test.go: -------------------------------------------------------------------------------- 1 | package string_test 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestCompare(t *testing.T) { 9 | compareTests := []struct { 10 | a, b string 11 | i int 12 | }{ 13 | {"", "", 0}, 14 | {"a", "", 1}, 15 | {"", "a", -1}, 16 | {"abc", "abc", 0}, 17 | {"ab", "abc", -1}, 18 | {"abc", "ab", 1}, 19 | {"x", "ab", 1}, 20 | {"ab", "x", -1}, 21 | {"x", "a", 1}, 22 | {"b", "x", -1}, 23 | // test runtime·memeq's chunked implementation 24 | {"abcdefgh", "abcdefgh", 0}, 25 | {"abcdefghi", "abcdefghi", 0}, 26 | {"abcdefghi", "abcdefghj", -1}, 27 | } 28 | 29 | for _, tt := range compareTests { 30 | cmp := strings.Compare(tt.a, tt.b) 31 | if cmp != tt.i { 32 | t.Errorf(`want %v, but Compare(%q, %q) = %v`, tt.i, tt.a, tt.b, cmp) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chapter8/sources/table_driven_strings_test.go: -------------------------------------------------------------------------------- 1 | package string_test 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestCompare(t *testing.T) { 9 | compareTests := []struct { 10 | a, b string 11 | i int 12 | }{ 13 | {"", "", 0}, 14 | {"a", "", 1}, 15 | {"", "a", -1}, 16 | } 17 | 18 | for _, tt := range compareTests { 19 | cmp := strings.Compare(tt.a, tt.b) 20 | if cmp != tt.i { 21 | t.Errorf(`want %v, but Compare(%q, %q) = %v`, tt.i, tt.a, tt.b, cmp) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter8/sources/table_driven_strings_with_map_test.go: -------------------------------------------------------------------------------- 1 | package string_test 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestCompare(t *testing.T) { 9 | compareTests := map[string]struct { 10 | a, b string 11 | i int 12 | }{ 13 | `compareTwoEmptyString`: {"", "", 0}, 14 | `compareSecondParamIsEmpty`: {"a", "", 1}, 15 | `compareFirstParamIsEmpty`: {"", "a", -1}, 16 | } 17 | 18 | for name, tt := range compareTests { 19 | t.Run(name, func(t *testing.T) { 20 | cmp := strings.Compare(tt.a, tt.b) 21 | if cmp != tt.i { 22 | t.Errorf(`want %v, but Compare(%q, %q) = %v`, tt.i, tt.a, tt.b, cmp) 23 | } 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter8/sources/table_driven_strings_with_subtest_test.go: -------------------------------------------------------------------------------- 1 | package string_test 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestCompare(t *testing.T) { 9 | compareTests := []struct { 10 | name, a, b string 11 | i int 12 | }{ 13 | {`compareTwoEmptyString`, "", "", 0}, 14 | {`compareSecondParamIsEmpty`, "a", "", 1}, 15 | {`compareFirstParamIsEmpty`, "", "a", -1}, 16 | } 17 | 18 | for _, tt := range compareTests { 19 | t.Run(tt.name, func(t *testing.T) { 20 | cmp := strings.Compare(tt.a, tt.b) 21 | if cmp != tt.i { 22 | t.Errorf(`want %v, but Compare(%q, %q) = %v`, tt.i, tt.a, tt.b, cmp) 23 | } 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter8/sources/testdata-demo1/testdata/attendee1.xml: -------------------------------------------------------------------------------- 1 | 2 | robpike 3 | 60 4 | 13912345678 5 | https://www.gophercon.com/speaker/robpike 6 | -------------------------------------------------------------------------------- /chapter8/sources/testdata-demo2/testdata/attendee1.golden: -------------------------------------------------------------------------------- 1 | 2 | robpike 3 | 60 4 | 13912345678 5 | https://www.gophercon.com/speaker/robpike 6 | -------------------------------------------------------------------------------- /chapter9/sources/go-bytes-and-strings/byte_slice_equality.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | fmt.Println(bytes.Equal([]byte{'a', 'b', 'c'}, []byte{'a', 'b', 'd'})) // false 10 | fmt.Println(bytes.Equal([]byte{'a', 'b', 'c'}, []byte{'a', 'b', 'c'})) // true 11 | fmt.Println(bytes.Equal([]byte{'a', 'b', 'c'}, []byte{'b', 'a', 'c'})) // false 12 | fmt.Println(bytes.Equal([]byte{}, nil)) // true 13 | } 14 | -------------------------------------------------------------------------------- /chapter9/sources/go-bytes-and-strings/byte_slice_test_equality_with_operator.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var a = []byte{'a', 'b', 'c'} 7 | var b = []byte{'a', 'b', 'd'} 8 | 9 | if a == b { // invalid operation: a == b 10 | fmt.Println("slice a is equal to slice b") 11 | } else { 12 | fmt.Println("slice a is not equal to slice b") 13 | } 14 | 15 | if a != nil { // valid operation 16 | fmt.Println("slice a is not nil") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter9/sources/go-bytes-and-strings/bytes_compare.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | var a = []byte{'a', 'b', 'c'} 10 | var b = []byte{'a', 'b', 'd'} 11 | var c = []byte{} //empty slice 12 | var d []byte //nil slice 13 | 14 | fmt.Println(bytes.Compare(a, b)) // -1 a < b 15 | fmt.Println(bytes.Compare(b, a)) // 1 b < a 16 | fmt.Println(bytes.Compare(c, d)) // 0 17 | fmt.Println(bytes.Compare(c, nil)) // 0 18 | fmt.Println(bytes.Compare(d, nil)) // 0 19 | fmt.Println(bytes.Compare(nil, nil)) // 0 nil == nil 20 | } 21 | -------------------------------------------------------------------------------- /chapter9/sources/go-bytes-and-strings/equalfold.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | fmt.Println(strings.EqualFold("GoLang", "golang")) // true 11 | fmt.Println(bytes.Equal([]byte("GoLang"), []byte("Golang"))) // false 12 | fmt.Println(bytes.EqualFold([]byte("GoLang"), []byte("Golang"))) // true 13 | } 14 | -------------------------------------------------------------------------------- /chapter9/sources/go-bytes-and-strings/join_and_builder.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | s := []string{"I", "love", "Go"} 11 | fmt.Println(strings.Join(s, " ")) // I love Go 12 | b := [][]byte{[]byte("I"), []byte("love"), []byte("Go")} 13 | fmt.Printf("%q\n", bytes.Join(b, []byte(" "))) // "I love Go" 14 | 15 | var builder strings.Builder 16 | for i, w := range s { 17 | builder.WriteString(w) 18 | if i != len(s)-1 { 19 | builder.WriteString(" ") 20 | } 21 | } 22 | fmt.Printf("%s\n", builder.String()) // I love Go 23 | 24 | var buf bytes.Buffer 25 | for i, w := range b { 26 | buf.Write(w) 27 | if i != len(b)-1 { 28 | buf.WriteString(" ") 29 | } 30 | } 31 | fmt.Printf("%s\n", buf.String()) // I love Go 32 | } 33 | -------------------------------------------------------------------------------- /chapter9/sources/go-bytes-and-strings/string_and_bytes_reader.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | var buf bytes.Buffer 12 | var s = "I love Go!!" 13 | 14 | _, err := io.Copy(&buf, strings.NewReader(s)) 15 | if err != nil { 16 | panic(err) 17 | } 18 | fmt.Printf("%q\n", buf.String()) // "I love Go!!" 19 | 20 | buf.Reset() 21 | var b = []byte("I love Go!!") 22 | _, err = io.Copy(&buf, bytes.NewReader(b)) 23 | if err != nil { 24 | panic(err) 25 | } 26 | fmt.Printf("%q\n", buf.String()) // "I love Go!!" 27 | } 28 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/c_array_to_go_slice.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // int cArray[] = {1, 2, 3, 4, 5, 6, 7}; 4 | import "C" 5 | import ( 6 | "fmt" 7 | "unsafe" 8 | ) 9 | 10 | func CArrayToGoArray(cArray unsafe.Pointer, elemSize uintptr, len int) (goArray []int32) { 11 | for i := 0; i < len; i++ { 12 | j := *(*int32)((unsafe.Pointer)(uintptr(cArray) + uintptr(i)*elemSize)) 13 | goArray = append(goArray, j) 14 | } 15 | 16 | return 17 | } 18 | 19 | func main() { 20 | goArray := CArrayToGoArray(unsafe.Pointer(&C.cArray[0]), unsafe.Sizeof(C.cArray[0]), 7) 21 | fmt.Println(goArray) 22 | } 23 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/c_char_array_to_go_byte_slice.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // char cArray[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g'}; 4 | import "C" 5 | import ( 6 | "fmt" 7 | "unsafe" 8 | ) 9 | 10 | func main() { 11 | goArray := C.GoBytes(unsafe.Pointer(&C.cArray[0]), 7) 12 | fmt.Printf("%c\n", goArray) // [a b c d e f g] 13 | } 14 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/c_enum.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // enum color { 4 | // RED, 5 | // BLUE, 6 | // YELLOW 7 | // }; 8 | import "C" 9 | import "fmt" 10 | 11 | func main() { 12 | var e, f, g C.enum_color = C.RED, C.BLUE, C.YELLOW 13 | fmt.Println(e, f, g) // 0 1 2 14 | } 15 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/c_errno.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // #include 4 | // #include 5 | // #include 6 | // int foo(int i) { 7 | // errno = 0; 8 | // if (i > 5) { 9 | // errno = 8; 10 | // return i - 5; 11 | // } else { 12 | // return i; 13 | // } 14 | //} 15 | import "C" 16 | import "fmt" 17 | 18 | func main() { 19 | i, err := C.foo(C.int(8)) 20 | if err != nil { 21 | fmt.Println(err) 22 | } else { 23 | fmt.Println(i) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/c_struct.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // #include 4 | // 5 | // struct employee { 6 | // char *id; 7 | // int age; 8 | // }; 9 | import "C" 10 | 11 | import ( 12 | "fmt" 13 | "unsafe" 14 | ) 15 | 16 | func main() { 17 | id := C.CString("1247") 18 | defer C.free(unsafe.Pointer(id)) 19 | 20 | var p = C.struct_employee{ 21 | id: id, 22 | age: 21, 23 | } 24 | fmt.Printf("%#v\n", p) 25 | } 26 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/c_type_size.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // struct employee { 4 | // char *id; 5 | // int age; 6 | // }; 7 | import "C" 8 | 9 | import ( 10 | "fmt" 11 | ) 12 | 13 | func main() { 14 | fmt.Printf("%#v\n", C.sizeof_int) // 4 15 | fmt.Printf("%#v\n", C.sizeof_char) // 1 16 | fmt.Printf("%#v\n", C.sizeof_struct_employee) // 16 17 | } 18 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/c_union_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // #include 4 | // union bar { 5 | // char c; 6 | // int i; 7 | // double d; 8 | // }; 9 | import "C" 10 | import "fmt" 11 | 12 | func main() { 13 | var b *C.union_bar = new(C.union_bar) 14 | b.c = 4 15 | fmt.Println(b) 16 | } 17 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/c_union_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // #include 4 | // union bar { 5 | // char c; 6 | // int i; 7 | // double d; 8 | // }; 9 | import "C" 10 | import "fmt" 11 | 12 | func main() { 13 | var b *C.union_bar = new(C.union_bar) 14 | b[0] = 4 15 | fmt.Println(b) 16 | } 17 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/cgo-perf/cgo_call.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // 4 | // void foo() { 5 | // } 6 | // 7 | import "C" 8 | 9 | func CallCFunc() { 10 | C.foo() 11 | } 12 | 13 | func foo() { 14 | 15 | } 16 | 17 | func CallGoFunc() { 18 | foo() 19 | } 20 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/cgo-perf/cgo_call_test.go: -------------------------------------------------------------------------------- 1 | // go test -bench . -gcflags '-l' 2 | package main 3 | 4 | import "testing" 5 | 6 | func BenchmarkCGO(b *testing.B) { 7 | for i := 0; i < b.N; i++ { 8 | CallCFunc() 9 | } 10 | } 11 | 12 | func BenchmarkGo(b *testing.B) { 13 | for i := 0; i < b.N; i++ { 14 | CallGoFunc() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/cgo_sleep.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //#include 4 | //void cgoSleep() { sleep(1000); } 5 | import "C" 6 | import ( 7 | "sync" 8 | ) 9 | 10 | func cgoSleep() { 11 | C.cgoSleep() 12 | } 13 | 14 | func main() { 15 | var wg sync.WaitGroup 16 | wg.Add(100) 17 | for i := 0; i < 100; i++ { 18 | go func() { 19 | cgoSleep() 20 | wg.Done() 21 | }() 22 | } 23 | 24 | wg.Wait() 25 | } 26 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/foo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "foo.h" 3 | 4 | int count = 6; 5 | void foo() { 6 | printf("I am foo!\n"); 7 | } 8 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/foo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // #cgo CFLAGS: -I${SRCDIR} 4 | // #cgo LDFLAGS: -L${SRCDIR} -lfoo 5 | // #include 6 | // #include 7 | // #include "foo.h" 8 | import "C" 9 | import "fmt" 10 | 11 | func main() { 12 | fmt.Println(C.count) 13 | C.foo() 14 | } 15 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/foo.h: -------------------------------------------------------------------------------- 1 | 2 | extern int count; 3 | void foo(); 4 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/go_sleep.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | func goSleep() { 9 | time.Sleep(time.Second * 10) 10 | } 11 | 12 | func main() { 13 | var wg sync.WaitGroup 14 | wg.Add(100) 15 | for i := 0; i < 100; i++ { 16 | go func() { 17 | goSleep() 18 | wg.Done() 19 | }() 20 | } 21 | 22 | wg.Wait() 23 | } 24 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/how_cgo_works.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // #include 4 | // #include 5 | // 6 | // void print(char *str) { 7 | // printf("%s\n", str); 8 | // } 9 | import "C" 10 | 11 | import "unsafe" 12 | 13 | func main() { 14 | s := "Hello, Cgo" 15 | cs := C.CString(s) 16 | defer C.free(unsafe.Pointer(cs)) 17 | C.print(cs) 18 | } 19 | -------------------------------------------------------------------------------- /chapter9/sources/go-cgo/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | cwd, err := os.Getwd() 11 | if err != nil { 12 | log.Fatal(err) 13 | } 14 | 15 | srv := &http.Server{ 16 | Addr: ":8000", 17 | Handler: http.FileServer(http.Dir(cwd)), 18 | } 19 | log.Fatal(srv.ListenAndServe()) 20 | } 21 | -------------------------------------------------------------------------------- /chapter9/sources/go-character-set-encoding/dump_utf8_encoding_of_string.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var s = "中" 7 | fmt.Printf("Unicode字符:%s => 其UTF-8内存编码表示为: ", s) 8 | for _, v := range []byte(s) { 9 | fmt.Printf("0x%X ", v) 10 | } 11 | fmt.Printf("\n") 12 | } 13 | -------------------------------------------------------------------------------- /chapter9/sources/go-character-set-encoding/gb18030.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter9/sources/go-character-set-encoding/gb18030.txt -------------------------------------------------------------------------------- /chapter9/sources/go-character-set-encoding/rune_encode_and_decode.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unicode/utf8" 6 | ) 7 | 8 | // rune -> []byte 9 | func encodeRune() { 10 | var r rune = 0x4E2D // 0x4E2D为Unicode字符"中"的码点 11 | buf := make([]byte, 3) 12 | n := utf8.EncodeRune(buf, r) 13 | 14 | fmt.Printf("the byte slice after encoding rune 0x4E2D is ") 15 | fmt.Printf("[ ") 16 | for i := 0; i < n; i++ { 17 | fmt.Printf("0x%X ", buf[i]) 18 | } 19 | fmt.Printf("]\n") 20 | fmt.Printf("the unicode character is %s\n", string(buf)) 21 | } 22 | 23 | // []byte -> rune 24 | func decodeRune() { 25 | var buf = []byte{0xE4, 0xB8, 0xAD} 26 | r, _ := utf8.DecodeRune(buf) 27 | fmt.Printf("the rune after decoding [0xE4, 0xB8, 0xAD] is 0x%X\n", r) 28 | } 29 | 30 | func main() { 31 | encodeRune() 32 | decodeRune() 33 | } 34 | -------------------------------------------------------------------------------- /chapter9/sources/go-character-set-encoding/utf16be-no-bom.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter9/sources/go-character-set-encoding/utf16be-no-bom.txt -------------------------------------------------------------------------------- /chapter9/sources/go-character-set-encoding/utf16be.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter9/sources/go-character-set-encoding/utf16be.txt -------------------------------------------------------------------------------- /chapter9/sources/go-character-set-encoding/utf32be-no-bom.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter9/sources/go-character-set-encoding/utf32be-no-bom.txt -------------------------------------------------------------------------------- /chapter9/sources/go-crypto/block_cipher_decrypt.pseudocode: -------------------------------------------------------------------------------- 1 | 2 | func main() { 3 | // 密钥(key) 4 | key := "这是用于分组密码算法解密的密钥串" 5 | 6 | // 创建分组密码算法实例 7 | XXXCipher := NewXXXCiper(key) 8 | 9 | // 初始向量(IV) -- 可选,亦可从密文字符串中提取(需加密方与解密方协商确定) 10 | IV := "这是初始向量" 11 | 12 | // 创建分组模式的实例 - 用于解密 13 | BlockModeDecrypter := NewBlockModeDecrypter(XXXCipher, IV) 14 | 15 | // 待解密的密文数据 16 | ciphertext := []byte{...} 17 | 18 | // 解密 19 | plaintext := BlockModeDecrypter.DecryptBlocks(ciphertext) 20 | 21 | // 输出明文 22 | fmt.Printf("%x\n", plaintext) 23 | } 24 | -------------------------------------------------------------------------------- /chapter9/sources/go-crypto/block_cipher_encrypt.pseudocode: -------------------------------------------------------------------------------- 1 | 2 | func main() { 3 | // 密钥(key) 4 | key := "这是用于分组密码算法加密的密钥串" 5 | 6 | // 创建分组密码算法实例 7 | XXXCipher := NewXXXCiper(key) 8 | 9 | // 初始向量(IV) -- 可选 10 | IV := "这是初始向量" 11 | 12 | // 创建分组模式的实例 - 用于加密 13 | BlockModeEncrypter := NewBlockModeEncrypter(XXXCipher, IV) 14 | 15 | // 待加密的明文字符串 16 | plaintext := "这是用于待加密的明文字符串" 17 | 18 | // 加密 19 | ciphertext := BlockModeEncrypter.EncryptBlocks(plaintext) 20 | 21 | // 输出密文 22 | fmt.Printf("%x\n", ciphertext) 23 | } 24 | -------------------------------------------------------------------------------- /chapter9/sources/go-crypto/hmac_generate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/hmac" 5 | "crypto/sha256" 6 | "fmt" 7 | ) 8 | 9 | func main() { 10 | // 密钥(key) 32字节 11 | key := []byte("12345678123456781234567812345678") 12 | 13 | // 要传递的消息 14 | message := []byte("I love go programming language!!") 15 | 16 | // 创建hmac实例(使用SHA-256单向散列函数) 17 | mac := hmac.New(sha256.New, key) 18 | mac.Write(message) 19 | 20 | // 计算mac值 21 | m := mac.Sum(nil) 22 | ms := fmt.Sprintf("%x", m) // mac to string 23 | fmt.Printf("mac值 = %s\n", ms) 24 | } 25 | -------------------------------------------------------------------------------- /chapter9/sources/go-crypto/rand_generate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/rand" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | c := 32 10 | b := make([]byte, c) 11 | _, err := rand.Read(b) 12 | if err != nil { 13 | panic(err) 14 | } 15 | fmt.Printf("%x\n", b) 16 | } 17 | -------------------------------------------------------------------------------- /chapter9/sources/go-crypto/rsa_key_generate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/rsa" 6 | "fmt" 7 | ) 8 | 9 | func main() { 10 | privateKey, err := rsa.GenerateKey(rand.Reader, 2048) 11 | if err != nil { 12 | panic(err) 13 | } 14 | publicKey := privateKey.PublicKey 15 | 16 | fmt.Printf("Private Key's size = %d bits\n", privateKey.Size()*8) 17 | fmt.Printf("Public Key's size = %d bits\n", publicKey.Size()*8) 18 | } 19 | -------------------------------------------------------------------------------- /chapter9/sources/go-crypto/rsa_pss_sign_and_verify.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto" 5 | "crypto/rand" 6 | "crypto/rsa" 7 | "crypto/sha256" 8 | "fmt" 9 | ) 10 | 11 | func main() { 12 | // 生成公钥密码的密钥对 13 | privateKey, err := rsa.GenerateKey(rand.Reader, 2048) 14 | if err != nil { 15 | panic(err) 16 | } 17 | publicKey := privateKey.PublicKey 18 | 19 | // 待签名消息 20 | msg := []byte("I love go programming language!!") 21 | 22 | // 计算摘要 23 | digest := sha256.Sum256(msg) 24 | 25 | // 用私钥签名 26 | sign, err := rsa.SignPSS(rand.Reader, privateKey, crypto.SHA256, digest[:], nil) 27 | if err != nil { 28 | panic(err) 29 | } 30 | fmt.Printf("签名:%s\n", fmt.Sprintf("%x", sign)) 31 | 32 | // 用公钥验证签名 33 | err = rsa.VerifyPSS(&publicKey, crypto.SHA256, digest[:], sign, nil) 34 | if err != nil { 35 | panic(err) 36 | } 37 | fmt.Printf("签名验证成功!\n") 38 | } 39 | -------------------------------------------------------------------------------- /chapter9/sources/go-crypto/sha256_sum.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/sha256" 5 | "fmt" 6 | ) 7 | 8 | func sum256(data []byte) string { 9 | sum := sha256.Sum256(data) 10 | return fmt.Sprintf("%x", sum) 11 | } 12 | 13 | func main() { 14 | s := "I love go programming language!!" 15 | fmt.Println(sum256([]byte(s))) 16 | } 17 | -------------------------------------------------------------------------------- /chapter9/sources/go-https/ca.srl: -------------------------------------------------------------------------------- 1 | B50AB1F42BD5FB1E 2 | -------------------------------------------------------------------------------- /chapter9/sources/go-https/hello.signed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter9/sources/go-https/hello.signed -------------------------------------------------------------------------------- /chapter9/sources/go-https/hello.txt: -------------------------------------------------------------------------------- 1 | hello,world 2 | -------------------------------------------------------------------------------- /chapter9/sources/go-https/hello.verify: -------------------------------------------------------------------------------- 1 | hello,world 2 | -------------------------------------------------------------------------------- /chapter9/sources/go-https/hello_world_server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 10 | fmt.Fprintf(w, "Hello, World!\n") 11 | }) 12 | http.ListenAndServe("localhost:8080", nil) 13 | } 14 | -------------------------------------------------------------------------------- /chapter9/sources/go-https/https_hello_world_server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 10 | fmt.Fprintf(w, "Hello, World!\n") 11 | }) 12 | fmt.Println(http.ListenAndServeTLS("localhost:8081", "server.crt", "server.key", nil)) 13 | } 14 | -------------------------------------------------------------------------------- /chapter9/sources/go-https/verify-dual-cert/client_verify_by_cacert.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | ) 10 | 11 | func main() { 12 | pool := x509.NewCertPool() 13 | caCertPath := "../ca.crt" 14 | 15 | caCrt, err := ioutil.ReadFile(caCertPath) 16 | if err != nil { 17 | fmt.Println("ReadFile err:", err) 18 | return 19 | } 20 | pool.AppendCertsFromPEM(caCrt) 21 | 22 | tr := &http.Transport{ 23 | TLSClientConfig: &tls.Config{RootCAs: pool}, 24 | } 25 | client := &http.Client{Transport: tr} 26 | resp, err := client.Get("https://localhost:8081") 27 | if err != nil { 28 | fmt.Println("Get error:", err) 29 | return 30 | } 31 | defer resp.Body.Close() 32 | body, err := ioutil.ReadAll(resp.Body) 33 | fmt.Println(string(body)) 34 | } 35 | -------------------------------------------------------------------------------- /chapter9/sources/go-https/verify-dual-cert/hello_world_server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | ) 10 | 11 | func main() { 12 | pool := x509.NewCertPool() 13 | caCertPath := "../ca.crt" 14 | 15 | caCrt, err := ioutil.ReadFile(caCertPath) 16 | if err != nil { 17 | fmt.Println("ReadFile err:", err) 18 | return 19 | } 20 | pool.AppendCertsFromPEM(caCrt) 21 | 22 | s := &http.Server{ 23 | Addr: "localhost:8081", 24 | Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 25 | fmt.Fprintf(w, "Hello, World!\n") 26 | }), 27 | TLSConfig: &tls.Config{ 28 | ClientCAs: pool, 29 | ClientAuth: tls.RequireAndVerifyClientCert, 30 | }, 31 | } 32 | 33 | fmt.Println(s.ListenAndServeTLS("../server-signed-by-ca.crt", "../server.key")) 34 | } 35 | -------------------------------------------------------------------------------- /chapter9/sources/go-https/verify-server-cert/client_skip_verify.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | ) 9 | 10 | func main() { 11 | tr := &http.Transport{ 12 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 13 | } 14 | client := &http.Client{Transport: tr} 15 | resp, err := client.Get("https://localhost:8081") 16 | 17 | if err != nil { 18 | fmt.Println("error:", err) 19 | return 20 | } 21 | defer resp.Body.Close() 22 | body, err := ioutil.ReadAll(resp.Body) 23 | fmt.Println(string(body)) 24 | } 25 | -------------------------------------------------------------------------------- /chapter9/sources/go-https/verify-server-cert/client_verify_by_cacert.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | ) 10 | 11 | func main() { 12 | pool := x509.NewCertPool() 13 | caCertPath := "../ca.crt" 14 | 15 | caCrt, err := ioutil.ReadFile(caCertPath) 16 | if err != nil { 17 | fmt.Println("ReadFile err:", err) 18 | return 19 | } 20 | pool.AppendCertsFromPEM(caCrt) 21 | 22 | tr := &http.Transport{ 23 | TLSClientConfig: &tls.Config{RootCAs: pool}, 24 | } 25 | client := &http.Client{Transport: tr} 26 | resp, err := client.Get("https://localhost:8081") 27 | if err != nil { 28 | fmt.Println("Get error:", err) 29 | return 30 | } 31 | defer resp.Body.Close() 32 | body, err := ioutil.ReadAll(resp.Body) 33 | fmt.Println(string(body)) 34 | } 35 | -------------------------------------------------------------------------------- /chapter9/sources/go-https/verify-server-cert/client_without_cacert.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | resp, err := http.Get("https://localhost:8081") 11 | if err != nil { 12 | fmt.Println("error:", err) 13 | return 14 | } 15 | defer resp.Body.Close() 16 | body, err := ioutil.ReadAll(resp.Body) 17 | fmt.Println(string(body)) 18 | } 19 | -------------------------------------------------------------------------------- /chapter9/sources/go-https/verify-server-cert/hello_world_server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 10 | fmt.Fprintf(w, "Hello, World!\n") 11 | }) 12 | fmt.Println(http.ListenAndServeTLS("localhost:8081", 13 | "../server-signed-by-ca.crt", 14 | "../server.key", nil)) 15 | } 16 | -------------------------------------------------------------------------------- /chapter9/sources/go-read-and-write/.bufio_write_byte_slice.go.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/chapter9/sources/go-read-and-write/.bufio_write_byte_slice.go.swp -------------------------------------------------------------------------------- /chapter9/sources/go-read-and-write/bufio.txt: -------------------------------------------------------------------------------- 1 | I love golang! 2 | I love golang! 3 | I love golang! 4 | -------------------------------------------------------------------------------- /chapter9/sources/go-read-and-write/bufio_write_byte_slice.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | file := "./bufio.txt" 11 | 12 | f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 13 | if err != nil { 14 | fmt.Println("open file error:", err) 15 | return 16 | } 17 | defer func() { 18 | f.Sync() 19 | f.Close() 20 | }() 21 | 22 | data := []byte("I love golang!\n") 23 | 24 | // 通过包裹函数创建带缓冲I/O的类型 25 | bio := bufio.NewWriterSize(f, 32) //初始缓冲区大小为32字节 26 | 27 | // 将15个字节写入bio缓冲区,缓冲区缓存15个字节,bufio.txt中内容仍为空 28 | bio.Write(data) 29 | 30 | // 将15个字节写入bio缓冲区,缓冲区缓存30个字节, bufio.txt中内容仍为空 31 | bio.Write(data) 32 | 33 | // 将15个字节写入bio缓冲区后,bufio将32个字节写入bufio.txt, 34 | // bio缓冲区中仍然缓存15*3-32个字节 35 | bio.Write(data) 36 | 37 | // 将bio缓冲区中所有缓存数据均写入bufio.txt 38 | bio.Flush() 39 | } 40 | -------------------------------------------------------------------------------- /chapter9/sources/go-read-and-write/gzip_compress_data.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "compress/gzip" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | file := "./hello_gopher.gz" 11 | f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 12 | if err != nil { 13 | fmt.Println("open file error:", err) 14 | return 15 | } 16 | defer f.Close() 17 | 18 | zw := gzip.NewWriter(f) 19 | defer zw.Close() 20 | _, err = zw.Write([]byte("hello, gopher! I love golang!!")) 21 | if err != nil { 22 | fmt.Println("write compressed data error:", err) 23 | } 24 | fmt.Println("write compressed data ok") 25 | } 26 | -------------------------------------------------------------------------------- /chapter9/sources/go-read-and-write/gzip_decompress_data.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "compress/gzip" 5 | "fmt" 6 | "io" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | file := "./hello_gopher.gz" 12 | f, err := os.Open(file) 13 | if err != nil { 14 | fmt.Println("open file error:", err) 15 | return 16 | } 17 | defer f.Close() 18 | 19 | zw, _ := gzip.NewReader(f) 20 | defer zw.Close() 21 | 22 | i := 1 23 | for { 24 | buf := make([]byte, 32) 25 | _, err = zw.Read(buf) 26 | if err != nil { 27 | if err == io.EOF { 28 | fmt.Printf("第%d次读取的压缩数据为: %q\n", i, buf) 29 | fmt.Println("读取到文件末尾,程序退出!") 30 | } else { 31 | fmt.Printf("第%d次读取压缩数据失败:%v", i, err) 32 | } 33 | return 34 | } 35 | fmt.Printf("第%d次读取的压缩数据为: %q\n", i, buf) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /chapter9/sources/go-reflect/call_func_and_method.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func Add(i, j int) int { 9 | return i + j 10 | } 11 | 12 | type Calculator struct{} 13 | 14 | func (c Calculator) Add(i, j int) int { 15 | return i + j 16 | } 17 | 18 | func main() { 19 | // 函数调用 20 | f := reflect.ValueOf(Add) 21 | var i = 5 22 | var j = 6 23 | vals := []reflect.Value{reflect.ValueOf(i), reflect.ValueOf(j)} 24 | ret := f.Call(vals) 25 | fmt.Println(ret[0].Int()) // 11 26 | 27 | // 方法调用 28 | c := reflect.ValueOf(Calculator{}) 29 | m := c.MethodByName("Add") 30 | ret = m.Call(vals) 31 | fmt.Println(ret[0].Int()) // 11 32 | 33 | var k float64 = 3.14 34 | ret = m.Call([]reflect.Value{reflect.ValueOf(i), 35 | reflect.ValueOf(k)}) // panic: reflect: Call using float64 as type int 36 | fmt.Println(ret[0].Int()) 37 | } 38 | -------------------------------------------------------------------------------- /chapter9/sources/go-reflect/reflect_value_to_interface.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | var i = 5 10 | val := reflect.ValueOf(i) 11 | r := val.Interface().(int) 12 | fmt.Println(r) // 5 13 | r = 6 14 | fmt.Println(i, r) // 5 6 15 | 16 | val = reflect.ValueOf(&i) 17 | q := val.Interface().(*int) 18 | fmt.Printf("%p, %p, %d\n", &i, q, *q) // 0xc0000b4008, 0xc0000b4008, 5 19 | *q = 7 20 | fmt.Println(i) // 7 21 | } 22 | -------------------------------------------------------------------------------- /chapter9/sources/go-signal/go-program-notify-lost-signal.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/signal" 7 | "syscall" 8 | "time" 9 | ) 10 | 11 | func main() { 12 | c := make(chan os.Signal, 1) 13 | signal.Notify(c, syscall.SIGINT) 14 | 15 | // 在这10s期间,我们多次触发SIGINT信号 16 | time.Sleep(10 * time.Second) 17 | 18 | for { 19 | select { 20 | case s := <-c: 21 | fmt.Println("c: 获取异步信号", s) 22 | default: 23 | fmt.Println("c: 没有信号, 退出") 24 | return 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /chapter9/sources/go-signal/go-program-notify-signal-twice-on-same-channel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/signal" 7 | "sync" 8 | "syscall" 9 | ) 10 | 11 | func main() { 12 | var wg sync.WaitGroup 13 | c := make(chan os.Signal, 2) 14 | 15 | signal.Notify(c, syscall.SIGINT) 16 | signal.Notify(c, syscall.SIGINT) 17 | 18 | // Block until any signal is received. 19 | wg.Add(1) 20 | go func() { 21 | for { 22 | s := <-c 23 | fmt.Println("c: 收到异步信号", s) 24 | } 25 | wg.Done() 26 | }() 27 | wg.Wait() 28 | } 29 | -------------------------------------------------------------------------------- /chapter9/sources/go-signal/go-program-notify-signal-twice.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/signal" 7 | "syscall" 8 | "time" 9 | ) 10 | 11 | func main() { 12 | c1 := make(chan os.Signal, 1) 13 | c2 := make(chan os.Signal, 1) 14 | 15 | signal.Notify(c1, syscall.SIGINT, syscall.SIGTERM) 16 | signal.Notify(c2, syscall.SIGINT, syscall.SIGTERM) 17 | 18 | go func() { 19 | s := <-c1 20 | fmt.Println("c1: 收到异步信号", s) 21 | }() 22 | 23 | s := <-c2 24 | fmt.Println("c2: 收到异步信号", s) 25 | time.Sleep(5 * time.Second) 26 | } 27 | -------------------------------------------------------------------------------- /chapter9/sources/go-signal/go-program-without-signal-handling.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | var wg sync.WaitGroup 12 | errChan := make(chan error, 1) 13 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 14 | fmt.Fprintf(w, "Hello, Signal!\n") 15 | }) 16 | wg.Add(1) 17 | go func() { 18 | errChan <- http.ListenAndServe("localhost:8080", nil) 19 | wg.Done() 20 | }() 21 | 22 | select { 23 | case <-time.After(2 * time.Second): 24 | fmt.Println("web server start ok") 25 | case err := <-errChan: 26 | fmt.Println("web server start failed:", err) 27 | } 28 | wg.Wait() 29 | fmt.Println("web server shutdown ok") 30 | } 31 | -------------------------------------------------------------------------------- /chapter9/sources/go-tcpsock/conn_close/client1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | log.Println("begin dial...") 11 | conn, err := net.Dial("tcp", ":8888") 12 | if err != nil { 13 | log.Println("dial error:", err) 14 | return 15 | } 16 | conn.Close() 17 | log.Println("close ok") 18 | 19 | var buf = make([]byte, 32) 20 | n, err := conn.Read(buf) 21 | if err != nil { 22 | log.Println("read error:", err) 23 | } else { 24 | log.Printf("read % bytes, content is %s\n", n, string(buf[:n])) 25 | } 26 | 27 | n, err = conn.Write(buf) 28 | if err != nil { 29 | log.Println("write error:", err) 30 | } else { 31 | log.Printf("write % bytes, content is %s\n", n, string(buf[:n])) 32 | } 33 | 34 | time.Sleep(time.Second * 1000) 35 | } 36 | -------------------------------------------------------------------------------- /chapter9/sources/go-tcpsock/conn_establish/client1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | ) 7 | 8 | func main() { 9 | log.Println("begin dial...") 10 | conn, err := net.Dial("tcp", ":8888") 11 | if err != nil { 12 | log.Println("dial error:", err) 13 | return 14 | } 15 | defer conn.Close() 16 | log.Println("dial ok") 17 | } 18 | -------------------------------------------------------------------------------- /chapter9/sources/go-tcpsock/conn_establish/client2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "time" 7 | ) 8 | 9 | func establishConn(i int) net.Conn { 10 | conn, err := net.Dial("tcp", ":8888") 11 | if err != nil { 12 | log.Printf("%d: dial error: %s", i, err) 13 | return nil 14 | } 15 | log.Println(i, ":connect to server ok") 16 | return conn 17 | } 18 | 19 | func main() { 20 | var sl []net.Conn 21 | for i := 1; i < 1000; i++ { 22 | conn := establishConn(i) 23 | if conn != nil { 24 | sl = append(sl, conn) 25 | } 26 | } 27 | 28 | time.Sleep(time.Second * 10000) 29 | } 30 | -------------------------------------------------------------------------------- /chapter9/sources/go-tcpsock/conn_establish/client3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | log.Println("begin dial...") 11 | conn, err := net.DialTimeout("tcp", "104.236.176.96:80", 2*time.Second) 12 | if err != nil { 13 | log.Println("dial error:", err) 14 | return 15 | } 16 | defer conn.Close() 17 | log.Println("dial ok") 18 | } 19 | -------------------------------------------------------------------------------- /chapter9/sources/go-tcpsock/conn_establish/server2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | l, err := net.Listen("tcp", ":8888") 11 | if err != nil { 12 | log.Println("error listen:", err) 13 | return 14 | } 15 | defer l.Close() 16 | log.Println("listen ok") 17 | 18 | var i int 19 | for { 20 | time.Sleep(time.Second * 10) 21 | if _, err := l.Accept(); err != nil { 22 | log.Println("accept error:", err) 23 | break 24 | } 25 | i++ 26 | log.Printf("%d: accept a new connection\n", i) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /chapter9/sources/go-tcpsock/read_write/client1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | log.Println("begin dial...") 11 | conn, err := net.Dial("tcp", ":8888") 12 | if err != nil { 13 | log.Println("dial error:", err) 14 | return 15 | } 16 | defer conn.Close() 17 | log.Println("dial ok") 18 | time.Sleep(time.Second * 10000) 19 | } 20 | -------------------------------------------------------------------------------- /chapter9/sources/go-tcpsock/read_write/client2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | "os" 8 | "time" 9 | ) 10 | 11 | func main() { 12 | if len(os.Args) <= 1 { 13 | fmt.Println("usage: go run client2.go YOUR_CONTENT") 14 | return 15 | } 16 | log.Println("begin dial...") 17 | conn, err := net.Dial("tcp", ":8888") 18 | if err != nil { 19 | log.Println("dial error:", err) 20 | return 21 | } 22 | defer conn.Close() 23 | log.Println("dial ok") 24 | 25 | time.Sleep(time.Second * 2) 26 | data := os.Args[1] 27 | conn.Write([]byte(data)) 28 | log.Println("send data ok") 29 | 30 | time.Sleep(time.Second * 10000) 31 | } 32 | -------------------------------------------------------------------------------- /chapter9/sources/go-tcpsock/read_write/client3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | "os" 8 | "time" 9 | ) 10 | 11 | func main() { 12 | if len(os.Args) <= 1 { 13 | fmt.Println("usage: go run client3.go YOUR_CONTENT") 14 | return 15 | } 16 | log.Println("begin dial...") 17 | conn, err := net.Dial("tcp", ":8888") 18 | if err != nil { 19 | log.Println("dial error:", err) 20 | return 21 | } 22 | defer conn.Close() 23 | log.Println("dial ok") 24 | 25 | time.Sleep(time.Second * 2) 26 | data := os.Args[1] 27 | conn.Write([]byte(data)) 28 | log.Println("send data ok") 29 | } 30 | -------------------------------------------------------------------------------- /chapter9/sources/go-tcpsock/read_write/client4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | log.Println("begin dial...") 11 | conn, err := net.Dial("tcp", ":8888") 12 | if err != nil { 13 | log.Println("dial error:", err) 14 | return 15 | } 16 | defer conn.Close() 17 | log.Println("dial ok") 18 | 19 | data := make([]byte, 65536) 20 | conn.Write(data) 21 | 22 | time.Sleep(time.Second * 10000) 23 | } 24 | -------------------------------------------------------------------------------- /chapter9/sources/go-tcpsock/read_write/client5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | log.Println("begin dial...") 11 | conn, err := net.Dial("tcp", ":8888") 12 | if err != nil { 13 | log.Println("dial error:", err) 14 | return 15 | } 16 | defer conn.Close() 17 | log.Println("dial ok") 18 | 19 | data := make([]byte, 65536) 20 | var total int 21 | for { 22 | n, err := conn.Write(data) 23 | if err != nil { 24 | total += n 25 | log.Printf("write %d bytes, error:%s\n", n, err) 26 | break 27 | } 28 | total += n 29 | log.Printf("write %d bytes this time, %d bytes in total\n", n, total) 30 | } 31 | 32 | log.Printf("write %d bytes in total\n", total) 33 | time.Sleep(time.Second * 10000) 34 | } 35 | -------------------------------------------------------------------------------- /chapter9/sources/go-tcpsock/read_write/client6.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | log.Println("begin dial...") 11 | conn, err := net.Dial("tcp", ":8888") 12 | if err != nil { 13 | log.Println("dial error:", err) 14 | return 15 | } 16 | defer conn.Close() 17 | log.Println("dial ok") 18 | 19 | data := make([]byte, 65536) 20 | var total int 21 | for { 22 | conn.SetWriteDeadline(time.Now().Add(time.Microsecond * 10)) 23 | n, err := conn.Write(data) 24 | if err != nil { 25 | total += n 26 | log.Printf("write %d bytes, error:%s\n", n, err) 27 | break 28 | } 29 | total += n 30 | log.Printf("write %d bytes this time, %d bytes in total\n", n, total) 31 | } 32 | 33 | log.Printf("write %d bytes in total\n", total) 34 | time.Sleep(time.Second * 10000) 35 | } 36 | -------------------------------------------------------------------------------- /chapter9/sources/go-tcpsock/server.go: -------------------------------------------------------------------------------- 1 | //server.go 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "net" 8 | ) 9 | 10 | func handleConn(c net.Conn) { 11 | defer c.Close() 12 | for { 13 | // read from the connection 14 | // ... ... 15 | // write to the connection 16 | //... ... 17 | } 18 | } 19 | 20 | func main() { 21 | l, err := net.Listen("tcp", ":8888") 22 | if err != nil { 23 | fmt.Println("listen error:", err) 24 | return 25 | } 26 | 27 | for { 28 | c, err := l.Accept() 29 | if err != nil { 30 | fmt.Println("accept error:", err) 31 | break 32 | } 33 | // start a new goroutine to handle 34 | // the new connection. 35 | go handleConn(c) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /chapter9/sources/go-time-operations/compare_two_time_with_equal.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | t := time.Now() 10 | fmt.Println(t) //北京时间 11 | 12 | loc, err := time.LoadLocation("America/New_York") 13 | if err != nil { 14 | fmt.Println("load time location failed:", err) 15 | return 16 | } 17 | 18 | t1 := t.In(loc) // 转换成美国东部纽约时间表示 19 | fmt.Println(t1) 20 | fmt.Println(t.Equal(t1)) 21 | } 22 | -------------------------------------------------------------------------------- /chapter9/sources/go-time-operations/compare_two_time_with_operator.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | t := time.Now() 10 | fmt.Println(t) //北京时间 11 | 12 | loc, err := time.LoadLocation("America/New_York") 13 | if err != nil { 14 | fmt.Println("load time location failed:", err) 15 | return 16 | } 17 | 18 | t1 := t.In(loc) // 转换成美国东部纽约时间表示 19 | fmt.Println(t1) 20 | fmt.Println(t == t1) 21 | } 22 | -------------------------------------------------------------------------------- /chapter9/sources/go-time-operations/construct_time_with_func_now.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | "unsafe" 7 | ) 8 | 9 | func dumpWallAndExt(t time.Time) { 10 | var hasMonotonic int 11 | 12 | // 输出wall字段的值 13 | pWall := (*uint64)(unsafe.Pointer(&t)) 14 | fmt.Printf("0x%X\n", *pWall) 15 | if (1<<63)&(*pWall) != 0 { 16 | hasMonotonic = 1 17 | } 18 | fmt.Printf("hasMonotonic = %d\n", hasMonotonic) 19 | 20 | // 输出ext字段的值 21 | pExt := (*int64)(unsafe.Pointer((uintptr(unsafe.Pointer(&t)) + unsafe.Sizeof(uint64(0))))) 22 | fmt.Printf("0x%X\n", *pExt) 23 | fmt.Printf("%d\n", *pExt/86400/365) // 粗略计算距今的年数 24 | } 25 | 26 | func main() { 27 | t := time.Now() 28 | dumpWallAndExt(t) 29 | } 30 | -------------------------------------------------------------------------------- /chapter9/sources/go-time-operations/convert_time_between_tz.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | locSrc, err := time.LoadLocation("America/Los_Angeles") 10 | if err != nil { 11 | fmt.Println("load time location failed:", err) 12 | return 13 | } 14 | 15 | t := time.Date(2020, 6, 18, 06, 0, 0, 0, locSrc) 16 | fmt.Println(t) // 美国西部洛杉矶时间,即太平洋时间 17 | 18 | locTo, err := time.LoadLocation("America/New_York") 19 | if err != nil { 20 | fmt.Println("load time location failed:", err) 21 | return 22 | } 23 | 24 | t1 := t.In(locTo) // 转换成美国东部纽约时间表示 25 | fmt.Println(t1) 26 | } 27 | -------------------------------------------------------------------------------- /chapter9/sources/go-time-operations/diff_two_time_with_sub.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func subTwoTimeHasMonotonic() { 9 | t1 := time.Now() 10 | time.Sleep(time.Second * 5) 11 | t2 := time.Now() 12 | diff := t2.Sub(t1) 13 | fmt.Printf("[hasMonotonic = 1] t2 - t1 = %v\n", diff) 14 | 15 | } 16 | 17 | func subTwoTimeNoMonotonic() { 18 | t1 := time.Date(2020, 6, 18, 0, 0, 0, 0, time.UTC) 19 | t2 := time.Date(2020, 6, 18, 12, 0, 0, 0, time.UTC) 20 | diff := t2.Sub(t1) 21 | fmt.Printf("[hasMonotonic = 0] t2 - t1 = %v\n", diff) 22 | } 23 | 24 | func main() { 25 | subTwoTimeHasMonotonic() 26 | subTwoTimeNoMonotonic() 27 | } 28 | -------------------------------------------------------------------------------- /chapter9/sources/go-time-operations/get_current_time.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | t := time.Now() 10 | fmt.Println(t) 11 | } 12 | -------------------------------------------------------------------------------- /chapter9/sources/go-time-operations/get_time_with_tz.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | t := time.Now() 10 | fmt.Println(t) //北京时间 11 | 12 | loc, err := time.LoadLocation("America/New_York") 13 | if err != nil { 14 | fmt.Println("load time location failed:", err) 15 | return 16 | } 17 | 18 | t1 := t.In(loc) // 转换成美国东部纽约时间表示 19 | fmt.Println(t1) 20 | } 21 | -------------------------------------------------------------------------------- /chapter9/sources/go-time-operations/strftime_in_c.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | time_t now = time(NULL); 6 | 7 | struct tm *localTm; 8 | localTm = localtime(&now); 9 | 10 | char strTime[100]; 11 | strftime(strTime, sizeof(strTime), "%Y-%m-%d %H:%M:%S", localTm); 12 | printf("%s\n", strTime); 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /chapter9/sources/go-time-operations/timeformat_in_c_way.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | fmt.Println(time.Now().Format("%Y-%m-%d %H:%M:%S")) 10 | } 11 | -------------------------------------------------------------------------------- /chapter9/sources/go-time-operations/timeformat_in_go_way.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | fmt.Println(time.Now().Format("2006年01月02日 15时04分05秒")) 10 | } 11 | -------------------------------------------------------------------------------- /chapter9/sources/go-time-operations/timer_create.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func create_timer_by_afterfunc() { 9 | _ = time.AfterFunc(1*time.Second, func() { 10 | fmt.Println("timer created by afterfunc fired!") 11 | }) 12 | } 13 | 14 | func create_timer_by_newtimer() { 15 | timer := time.NewTimer(2 * time.Second) 16 | select { 17 | case <-timer.C: 18 | fmt.Println("timer created by newtimer fired!") 19 | } 20 | } 21 | 22 | func create_timer_by_after() { 23 | select { 24 | case <-time.After(2 * time.Second): 25 | fmt.Println("timer created by after fired!") 26 | } 27 | } 28 | 29 | func main() { 30 | create_timer_by_afterfunc() 31 | create_timer_by_newtimer() 32 | create_timer_by_after() 33 | } 34 | -------------------------------------------------------------------------------- /chapter9/sources/go-unsafe/c_is_not_type_safe.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int a = 0x12345678; 5 | unsigned char *p = (unsigned char*)&a; 6 | printf("0x%x\n", a); 7 | *p = 0x23; 8 | *(p+1) = 0x45; 9 | *(p+2) = 0x67; 10 | *(p+3) = 0x8a; 11 | printf("0x%x\n", a); 12 | } 13 | -------------------------------------------------------------------------------- /chapter9/sources/go-unsafe/go_is_not_type_safe.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | var a uint32 = 0x12345678 10 | fmt.Printf("0x%x\n", a) 11 | 12 | p := (unsafe.Pointer)(&a) 13 | 14 | b := (*[4]byte)(p) 15 | b[0] = 0x23 16 | b[1] = 0x45 17 | b[2] = 0x67 18 | b[3] = 0x8a 19 | 20 | fmt.Printf("0x%x\n", a) 21 | } 22 | -------------------------------------------------------------------------------- /chapter9/sources/go-unsafe/go_is_type_safe.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | a := 0x12345678 7 | fmt.Printf("0x%x\n", a) 8 | 9 | /* 10 | var p *byte = (*byte)(&a) 11 | *p = 0x23 12 | */ 13 | 14 | var b byte = byte(a) 15 | b = 0x23 16 | fmt.Printf("0x%x\n", b) 17 | fmt.Printf("0x%x\n", a) 18 | } 19 | -------------------------------------------------------------------------------- /chapter9/sources/go-unsafe/go_math_float64bits_vs_explicit_type_convertion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | func main() { 9 | var f float64 = 3.1415 10 | var d1 = uint64(f) 11 | var d2 = math.Float64bits(f) 12 | fmt.Printf("d1 = %d, d2 = %d\n", d1, d2) 13 | } 14 | -------------------------------------------------------------------------------- /chapter9/sources/go-unsafe/go_mem_align_under_pattern_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | var a = [10]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} 10 | var p = (*uint64)(unsafe.Pointer(&a[5])) 11 | 12 | fmt.Printf("a[5]的地址: 0x%p\n", &a[5]) 13 | fmt.Printf("a[5]的对齐系数: %d\n", unsafe.Alignof(a[5])) 14 | fmt.Printf("p的地址: 0x%p\n", p) 15 | fmt.Printf("p的对齐系数: %d\n", unsafe.Alignof(p)) 16 | fmt.Printf("*p = %d\n", *p) 17 | } 18 | -------------------------------------------------------------------------------- /chapter9/sources/go-unsafe/go_slice_and_string_header.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "unsafe" 7 | ) 8 | 9 | func newSlice() *[]byte { 10 | var b = []byte("hello, gopher") 11 | return &b 12 | } 13 | 14 | func main() { 15 | bh := (*reflect.SliceHeader)(unsafe.Pointer(newSlice())) 16 | var p = (*[]byte)(unsafe.Pointer(bh)) 17 | fmt.Printf("%q\n", *p) 18 | 19 | var a = [...]byte{'I', ' ', 'l', 'o', 'v', 'e', ' ', 'G', 'o', '!', '!'} 20 | bh.Data = uintptr(unsafe.Pointer(&a)) 21 | bh.Len = len(a) 22 | bh.Cap = len(a) 23 | 24 | fmt.Printf("%q\n", *p) 25 | } 26 | -------------------------------------------------------------------------------- /chapter9/sources/go-unsafe/go_slice_and_string_header_wrong_case.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "runtime" 7 | "time" 8 | "unsafe" 9 | ) 10 | 11 | func finalizer(p *[11]byte) { 12 | fmt.Println("数组对象被垃圾回收") 13 | } 14 | 15 | func newArray() *[11]byte { 16 | var a = [...]byte{'I', ' ', 'l', 'o', 'v', 'e', ' ', 'G', 'o', '!', '!'} 17 | runtime.SetFinalizer(&a, finalizer) 18 | return &a 19 | } 20 | 21 | func main() { 22 | var bh reflect.SliceHeader 23 | bh.Data = uintptr(unsafe.Pointer(newArray())) 24 | bh.Len = 11 25 | bh.Cap = 11 26 | var p = (*[]byte)(unsafe.Pointer(&bh)) 27 | for i := 0; i < 3; i++ { 28 | runtime.GC() 29 | time.Sleep(1 * time.Second) 30 | } 31 | fmt.Printf("%q\n", *p) //??? 32 | } 33 | -------------------------------------------------------------------------------- /chapter9/sources/go-unsafe/go_stack_obj_ref_by_uintptr.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | var x = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} 10 | fmt.Printf("变量x的值=%v\n", x) 11 | println("变量x的地址=", &x) 12 | 13 | var p = uintptr(unsafe.Pointer(&x)) 14 | var q = unsafe.Pointer(&x) 15 | 16 | a(x) // 执行一系列函数调用 17 | 18 | // 变更数组x中元素的值 19 | for i := 0; i < 10; i++ { 20 | x[i] = x[i] + 10 21 | } 22 | 23 | println("栈扩容后,变量x的地址=", &x) 24 | fmt.Printf("栈扩容后,变量x的值=%d\n", x) 25 | 26 | fmt.Printf("变量p(uintptr)存储的地址上的值=%d\n", *(*[10]int)(unsafe.Pointer(p))) 27 | fmt.Printf("变量q(unsafe.Pointer)引用的地址上的值=%d\n", *(*[10]int)(q)) 28 | } 29 | 30 | func a(x [10]int) { 31 | var y [100]int 32 | b(y) 33 | } 34 | 35 | func b(x [100]int) { 36 | var y [1000]int 37 | c(y) 38 | } 39 | 40 | func c(x [1000]int) { 41 | } 42 | -------------------------------------------------------------------------------- /chapter9/sources/go-unsafe/go_unsafe_compiler_checkptr.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "unsafe" 5 | ) 6 | 7 | func main() { 8 | var n = 5 9 | b := make([]byte, n) 10 | end := unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(n+10)) 11 | _ = end 12 | } 13 | -------------------------------------------------------------------------------- /cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigwhite/GoProgrammingFromBeginnerToMaster/c0b790a1fa0506386c84e0bfbf2f42ed0db6ba11/cover.png --------------------------------------------------------------------------------