├── .dockerignore ├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── ci.yaml │ └── github-actions-demo.yml ├── .gitignore ├── .golangci.yaml ├── 17x ├── binaryy │ └── main.go ├── c │ └── worker.c ├── ctx │ └── ctx.go ├── exec │ └── main.go ├── h2 │ ├── assets │ │ ├── cert.pem │ │ └── key.pem │ └── main.go ├── han │ └── main.go ├── html │ └── main.go ├── ient │ ├── ent │ │ ├── client.go │ │ ├── config.go │ │ ├── context.go │ │ ├── ent.go │ │ ├── enttest │ │ │ └── enttest.go │ │ ├── generate.go │ │ ├── hook │ │ │ └── hook.go │ │ ├── migrate │ │ │ ├── migrate.go │ │ │ └── schema.go │ │ ├── mutation.go │ │ ├── predicate │ │ │ └── predicate.go │ │ ├── runtime.go │ │ ├── runtime │ │ │ └── runtime.go │ │ ├── schema │ │ │ └── user.go │ │ ├── tx.go │ │ ├── user.go │ │ ├── user │ │ │ ├── user.go │ │ │ └── where.go │ │ ├── user_create.go │ │ ├── user_delete.go │ │ ├── user_query.go │ │ └── user_update.go │ └── start │ │ └── start.go ├── leetcode │ ├── 1-two_sum.go │ ├── 1-two_sum_test.go │ └── common.go ├── painkiller │ ├── pill.go │ └── pill_string.go ├── pow │ ├── t.go │ └── t_test.go ├── print │ └── print.go ├── sync_pool │ └── p_test.go ├── test │ ├── interface.go │ ├── lb │ │ └── main.go │ ├── selfrewrite.go │ └── t │ │ └── t_test.go └── trace.go ├── 7days └── orm │ ├── 17xorm.go │ ├── cmd │ └── main.go │ ├── dialect │ ├── dialect.go │ └── sqlite3.go │ ├── log │ └── logger.go │ ├── schema │ └── schema.go │ └── session │ ├── raw.go │ └── table.go ├── Docker.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── a-tutorials ├── advanced │ ├── 01-string │ │ ├── concat_string_test.go │ │ ├── string.go │ │ └── string_test.go │ ├── 02-slice │ │ └── slice.go │ ├── 04-map │ │ └── map.go │ ├── 06-closure │ │ └── closure.go │ ├── 07-function │ │ └── function.go │ ├── 08-defer │ │ └── defer.go │ ├── 09-panic-recover │ │ └── panic.go │ ├── 11-interface │ │ ├── 17x.txt │ │ └── interface.go │ ├── 12-type-assert │ │ ├── 17x.txt │ │ └── assert.go │ ├── 13-reflect │ │ └── reflect.go │ ├── benchmark │ │ └── forrange │ │ │ ├── README.md │ │ │ ├── forrange_test.go │ │ │ ├── point_test.go │ │ │ ├── struct_test.go │ │ │ └── unit_test.go │ ├── bytealignment │ │ └── main.go │ └── rand │ │ └── rand.go ├── base │ ├── README.md │ ├── channel │ │ ├── channel_test.go │ │ ├── once.go │ │ ├── os_test.go │ │ ├── rwmutex.go │ │ ├── semaphore.go │ │ └── waitgroup.go │ ├── colly │ │ └── colly.go │ ├── http │ │ ├── 01_http.go │ │ ├── 02_http_client.go │ │ └── 03_http_pprof.go │ ├── io │ │ ├── bufio.go │ │ ├── io_interface.go │ │ ├── os.go │ │ ├── std.go │ │ └── string_reader.go │ ├── lessons │ │ ├── advance │ │ │ └── unsafe.go │ │ ├── factory │ │ │ ├── main │ │ │ │ └── 21_Factory.go │ │ │ └── model │ │ │ │ ├── person.go │ │ │ │ └── student.go │ │ ├── mid │ │ │ ├── 27_Channel.go │ │ │ ├── 28_Reflect.go │ │ │ ├── common │ │ │ │ └── worker.go │ │ │ ├── context.go │ │ │ ├── currentmap.go │ │ │ ├── goroutine.go │ │ │ ├── goroutine_exit.go │ │ │ ├── goroutine_test.go │ │ │ ├── interface.go │ │ │ ├── intmap.go │ │ │ ├── run_worker.go │ │ │ └── syncmap.go │ │ ├── pipeline │ │ │ ├── fanin │ │ │ │ └── fanin.go │ │ │ └── hello │ │ │ │ └── simple.go │ │ └── simple │ │ │ ├── 01-hello │ │ │ └── hello.go │ │ │ ├── 02-datastructure │ │ │ ├── base │ │ │ │ ├── array.go │ │ │ │ └── string.go │ │ │ ├── pointer │ │ │ │ └── pointer.go │ │ │ ├── quote │ │ │ │ ├── channel.go │ │ │ │ ├── map.go │ │ │ │ └── slice.go │ │ │ └── struct.go │ │ │ ├── 03-printf │ │ │ └── print_format.go │ │ │ ├── 04-var_define │ │ │ └── var_define.go │ │ │ ├── 05-condition │ │ │ └── condition.go │ │ │ ├── 06-function │ │ │ ├── closure.go │ │ │ ├── defer.go │ │ │ ├── exception.go │ │ │ ├── function.go │ │ │ ├── params.go │ │ │ └── recursive.go │ │ │ ├── 07_method │ │ │ ├── extends.go │ │ │ └── method.go │ │ │ ├── 08_interface │ │ │ ├── faq.go │ │ │ └── interface.go │ │ │ ├── 09_others │ │ │ ├── automic.go │ │ │ ├── defer.go │ │ │ ├── err.go │ │ │ ├── file.go │ │ │ ├── flag.go │ │ │ ├── http.go │ │ │ ├── io.go │ │ │ ├── json.go │ │ │ ├── panic.go │ │ │ ├── range.go │ │ │ ├── sort.go │ │ │ └── time.go │ │ │ └── dmeo.go │ ├── mypprof │ │ ├── httpserver │ │ │ └── main.go │ │ ├── main.go │ │ └── trace │ │ │ └── trace.go │ ├── mytesttt │ │ ├── fib.go │ │ └── fib_test.go │ ├── network │ │ ├── client.go │ │ └── server.go │ ├── prime_number │ │ └── prime_number.go │ ├── second_lession │ │ ├── network │ │ │ ├── http │ │ │ │ ├── 01-http.go │ │ │ │ ├── 02-http-custom.go │ │ │ │ └── 02-http-trace.go │ │ │ └── net │ │ │ │ ├── net.go │ │ │ │ └── socket │ │ │ │ ├── client.go │ │ │ │ └── server.go │ │ └── timer │ │ │ └── ticker_timer.go │ ├── sync │ │ ├── cond.go │ │ ├── map.go │ │ ├── mutex.go │ │ ├── nocopy.go │ │ ├── once.go │ │ ├── pm2.config.json │ │ └── waitgroup.go │ └── t │ │ └── recover.go └── lib │ ├── ctx │ ├── withcancel.go │ ├── withtimeout.go │ └── withvalue.go │ ├── sync_cond │ └── main.go │ └── sync_pool │ ├── main.go │ └── p_test.go ├── algorithm ├── agc │ ├── recursion.go │ └── tower │ │ └── tower.go ├── common │ ├── lfu_ache.go │ ├── lfu_ache_test.go │ ├── lru_cache.go │ ├── lru_cache_test.go │ ├── ring_buffer.go │ ├── ring_buffer_test.go │ ├── stack.go │ └── stack_test.go ├── geektime │ ├── array-linkedlist-skiplist │ │ ├── 1-283_move-zeroes.go │ │ ├── 1-283_move-zeroes_test.go │ │ ├── 10-26-remove-duplicates-from-sorted-array.go │ │ ├── 11-189-rotate-array.go │ │ ├── 12-21-merge-two-sorted-lists.go │ │ ├── 13-88-merge-sorted-array.go │ │ ├── 14-66-plus-one.go │ │ ├── 2-11_container-with-most-water.go │ │ ├── 3-70_climbing-stairs.go │ │ ├── 4-15_3sum.go │ │ ├── 4.1-1_two-sum.go │ │ ├── 5-206_reverse-linked-list.go │ │ ├── 6_24_swap-nodes-in-pairs.go │ │ ├── 7-141_linked-list-cycle.go │ │ ├── 8-142_linked-list-cycle-ii.go │ │ ├── 8-142_linked-list-cycle-ii.md │ │ ├── 8-142_linked-list-cycle-ii.png │ │ └── 9-25_reverse-nodes-in-k-group.go │ ├── bfsdfs │ │ ├── 1-102-binary-tree-level-order-traversal.go │ │ ├── 1-102-binary-tree-level-order-traversal_test.go │ │ ├── 2-433-minimum-genetic-mutation.go │ │ ├── 3-22-generate-parentheses.go │ │ ├── 4-515-find-largest-value-in-each-tree-row.go │ │ ├── 5-127-word-ladder.go │ │ ├── 6-200-number-of-islands.go │ │ ├── 7-529-minesweeper.go │ │ ├── 8-126-word-ladder-ii.go │ │ ├── bfs_template.go │ │ ├── dfs_template.go │ │ └── node.go │ ├── binary-search │ │ ├── 1-69-sqrtx.go │ │ ├── 1-69-sqrtx_test.go │ │ ├── 2-367-valid-perfect-square.go │ │ ├── 3-33-search-in-rotated-sorted-array.go │ │ └── template.go │ ├── divide-conquer-backtracking │ │ ├── 1-50-powx-n.go │ │ ├── 2-78-subsets.go │ │ ├── 3-169-majority-element.go │ │ ├── 4-17-letter-combinations-of-a-phone-number.go │ │ ├── 5-51-n-queens.go │ │ └── template.go │ ├── fibonacci.go │ ├── fibonacci_test.go │ ├── greedy │ │ ├── 1-322-coin-change.go │ │ ├── 2-455-assign-cookies.go │ │ ├── 3-860-lemonade-change.go │ │ ├── 4-122-best-time-to-buy-and-sell-stock-ii.go │ │ ├── 5-874-walking-robot-simulation.go │ │ └── template.go │ ├── hash-map-set │ │ ├── 1-242-valid-anagram.go │ │ ├── 1-242-valid-anagram_test.go │ │ ├── 2-49-group-anagrams.go │ │ └── 3-1-two-sum.go │ ├── recursion │ │ ├── 1-70-climbing-stairs.go │ │ ├── 1-70-climbing-stairs_test.go │ │ ├── 10-77-combinations.go │ │ ├── 2-22-generate-parentheses.go │ │ ├── 2-22-generate-parentheses_test.go │ │ ├── 3-226-invert-binary-tree.go │ │ ├── 4-98-validate-binary-search-tree.go │ │ ├── 5-104-maximum-depth-of-binary-tree.go │ │ ├── 6-111-minimum-depth-of-binary-tree.go │ │ ├── 7-297-serialize-and-deserialize-binary-tree.go │ │ ├── 8-236-lowest-common-ancestor-of-a-binary-tree.go │ │ ├── 9-105-construct-binary-tree-from-preorder-and-inorder-traversal.go │ │ ├── model.go │ │ └── template.go │ ├── stack-queue-deque │ │ ├── 1-20-valid-parentheses.go │ │ ├── 2-155-min-stack.go │ │ ├── 2-155-min-stack_test.go │ │ ├── 3-84-largest-rectangle-in-histogram.go │ │ ├── 3-84-largest-rectangle-in-histogram_test.go │ │ └── 4-239-sliding-window-maximum.go │ └── tree │ │ ├── 1-94-binary-tree-inorder-traversal.go │ │ ├── 2-144-binary-tree-preorder-traversal.go │ │ ├── 3-509-n-ary-tree-postorder-traversal.go │ │ ├── 4-589-n-ary-tree-preorder-traversal.go │ │ ├── 5-429-n-ary-tree-level-order-traversal.go │ │ └── model.go ├── leetcode │ ├── array │ │ ├── difficult │ │ │ └── find_median_sorted_arrays.go │ │ ├── middle │ │ │ ├── 495-teemo-attacking.go │ │ │ └── subsets.go │ │ └── simple │ │ │ └── two_sum.go │ ├── daily │ │ ├── 1018-binary-prefix-divisible-by-5.go │ │ ├── 103-binary-tree-zigzag-level-order-traversal.go │ │ ├── 103-binary-tree-zigzag-level-order-traversal_test.go │ │ ├── 1046-last-stone-weight.go │ │ ├── 1046-last-stone-weight_test.go │ │ ├── 1128.go │ │ ├── 1128_test.go │ │ ├── 1202-smallest-string-with-swaps.go │ │ ├── 135-candy.go │ │ ├── 135-candy_test.go │ │ ├── 188-best-time-to-buy-and-sell-stock-iv.go │ │ ├── 188-best-time-to-buy-and-sell-stock-iv_test.go │ │ ├── 189-rotate-array.go │ │ ├── 205-isomorphic-strings.go │ │ ├── 205-isomorphic-strings_test.go │ │ ├── 217-contains-duplicate.go │ │ ├── 228-summary-ranges.go │ │ ├── 228-summary-ranges_test.go │ │ ├── 290-word-pattern.go │ │ ├── 290-word-pattern_test.go │ │ ├── 330-patching-array.go │ │ ├── 376-wiggle-subsequence.go │ │ ├── 387-first-unique-character-in-a-string.go │ │ ├── 387-first-unique-character-in-a-string_test.go │ │ ├── 389-find-the-difference.go │ │ ├── 399-evaluate-division.go │ │ ├── 424.go │ │ ├── 424_test.go │ │ ├── 435-non-overlapping-intervals.go │ │ ├── 455-assign-cookies.go │ │ ├── 455-assign-cookies_test.go │ │ ├── 480.go │ │ ├── 480_test.go │ │ ├── 49-group-anagrams.go │ │ ├── 509-fibonacci-number.go │ │ ├── 509-fibonacci-number_test.go │ │ ├── 62-unique-paths.go │ │ ├── 628-maximum-product-of-three-numbers.go │ │ ├── 628-maximum-product-of-three-numbers_test.go │ │ ├── 649-dota2-senate.go │ │ ├── 714-best-time-to-buy-and-sell-stock-with-transaction-fee.go │ │ ├── 721-accounts-merge.go │ │ ├── 738-monotone-increasing-digits.go │ │ ├── 738-monotone-increasing-digits_test.go │ │ ├── 746-min-cost-climbing-stairs.go │ │ ├── 746-min-cost-climbing-stairs_test.go │ │ ├── 830-positions-of-large-groups.go │ │ ├── 830-positions-of-large-groups_test.go │ │ ├── 86-partition-list.go │ │ ├── 860-lemonade-change.go │ │ ├── 888.go │ │ ├── 888_test.go │ │ ├── 989.go │ │ └── 989_test.go │ ├── demo │ │ └── demo.go │ ├── lcof │ │ ├── 03.go │ │ ├── 03_test.go │ │ ├── 04.go │ │ ├── 04_test.go │ │ ├── 05.go │ │ ├── 05_test.go │ │ ├── 06.go │ │ ├── 07.go │ │ ├── 09.go │ │ ├── 10-1.go │ │ ├── 10-1_test.go │ │ ├── 10-2.go │ │ ├── 10-2_test.go │ │ ├── 11.go │ │ ├── 12.go │ │ ├── 13.go │ │ ├── 13_test.go │ │ ├── 14-2.go │ │ ├── 14-2_test.go │ │ ├── 14.go │ │ ├── 14_test.go │ │ ├── 15.go │ │ ├── 15_test.go │ │ ├── 16.go │ │ ├── 17.go │ │ ├── 17_test.go │ │ ├── 18.go │ │ ├── 21.go │ │ ├── 22.go │ │ ├── 24.go │ │ └── model.go │ ├── linkedlist │ │ ├── README.md │ │ ├── middle │ │ │ ├── add_two_numbers.go │ │ │ ├── detect_cycle.go │ │ │ ├── detect_cycle.md │ │ │ └── detect_cycle.png │ │ └── simple │ │ │ ├── delete_node.go │ │ │ ├── get_intersection_node.go │ │ │ ├── is_palindrome.go │ │ │ ├── kth_to_last.go │ │ │ ├── partition.go │ │ │ └── remove_duplicate_nodes.go │ ├── matrix │ │ └── middle │ │ │ ├── rotate.go │ │ │ └── set_zeroes.go │ ├── number │ │ ├── 3.go │ │ └── 3_test.go │ ├── string │ │ ├── middle │ │ │ ├── length_of_longest_substring.go │ │ │ └── one_edit_way.go │ │ └── simple │ │ │ ├── can_permute_palindrome.go │ │ │ ├── check_permutation.go │ │ │ ├── compress_string.go │ │ │ ├── is_fliped_string.go │ │ │ ├── is_unique.go │ │ │ ├── replace_spaces.go │ │ │ └── str_str.go │ └── tree │ │ ├── difficult │ │ ├── common.go │ │ ├── max_path_sum.go │ │ └── max_path_sum_test.go │ │ ├── medium │ │ ├── 04.03-list-of-depth-lcci.go │ │ ├── 04.03-list-of-depth-lcci_test.go │ │ ├── 95.go │ │ ├── 95_test.go │ │ ├── 96.go │ │ ├── 98.go │ │ └── common.go │ │ └── simple │ │ ├── 100.go │ │ ├── 101.go │ │ ├── 102.go │ │ ├── 103.go │ │ ├── 104.go │ │ ├── 104_test.go │ │ ├── common.go │ │ ├── is_balanced.go │ │ └── is_balanced_test.go ├── others │ ├── bit_count.go │ ├── hyperloglog.go │ └── hyperloglog_test.go ├── similarity │ ├── README.md │ ├── seg.go │ ├── simhash │ │ └── simhash.go │ ├── t │ │ ├── similarity.go │ │ └── similarity_test.go │ ├── tfidf │ │ └── tfidf.go │ └── tokenizer │ │ ├── dictionary.txt │ │ ├── stopwords.txt │ │ └── tokenizer.go └── sort │ ├── bubble_sort.go │ ├── bubble_sort_test.go │ ├── insertion_sort.go │ ├── insertion_sort_test.go │ ├── quicksort.go │ ├── quicksort_test.go │ ├── selection_sort.go │ └── selection_sort_test.go ├── apm ├── logging │ ├── cerebro.yml │ ├── elasticsearch.yml │ ├── esexporter.yml │ ├── filebeat.conf.yml │ ├── filebeat.yml │ ├── kibana.yml │ ├── logstash.conf │ ├── logstash.yml │ └── t.go ├── prometheus │ ├── alert-rules.yml │ ├── alertmanager.yml │ ├── cadvisor.yml │ ├── docker-compose.yml │ ├── grafana.yml │ ├── node-exporter.yml │ └── prometheus.yml └── trace │ ├── config │ └── config.go │ ├── docker-compose.yml │ ├── gin │ ├── cmd │ │ ├── cmd.go │ │ └── gin.http │ ├── middleware │ │ └── jaeger.go │ └── router │ │ └── router.go │ ├── grpc │ ├── interceptor │ │ └── interceptor.go │ └── proto │ │ └── hello │ │ ├── client │ │ └── hello_client.go │ │ ├── proto │ │ ├── hello.pb.go │ │ └── hello.proto │ │ └── server │ │ └── hello_server.go │ ├── jaeger-agent.yml │ ├── jaeger-es.yml │ ├── jaeger.yml │ ├── kibana.yml │ ├── lesson1 │ ├── build.bat │ └── hello.go │ ├── lesson2 │ └── hello.go │ ├── lesson3 │ ├── client │ │ └── hello.go │ ├── formatter │ │ └── formatter.go │ └── publisher │ │ └── publisher.go │ └── lesson4 │ ├── client │ └── hello.go │ ├── formatter │ └── formatter.go │ └── publisher │ └── publisher.go ├── assets └── jetbrains-variant.svg ├── cgo ├── 2.go ├── fork.c ├── fork3.c ├── hello.go ├── helloworld.c ├── helloworld.go ├── helloworld.s ├── signal.c └── tmp.c ├── cloud-natinve ├── certs │ ├── certs.go │ └── certs_test.go ├── clientgo │ ├── clientset │ │ ├── main.go │ │ └── refactor.go │ ├── discovery-client │ │ └── main.go │ ├── dynamic-client │ │ └── main.go │ ├── key.go │ ├── kubeconfig │ ├── rest-client │ │ └── main.go │ └── webterminal │ │ └── main.go ├── cobra-demo │ ├── cmd │ │ ├── hello.go │ │ ├── root.go │ │ └── version.go │ ├── demo │ │ └── demo1.go │ └── main.go ├── corefile │ ├── parse.go │ └── parse_test.go ├── health-check │ ├── reachable.go │ └── reachable_test.go ├── oci │ └── client.go ├── ssh │ ├── client.go │ ├── helper.go │ ├── result.go │ ├── ssh.go │ ├── ssh_test.go │ └── timeout.go ├── toolbar │ └── main.go └── tunnel │ ├── http │ └── demo │ │ ├── origin │ │ └── main.go │ │ ├── reverseproxy │ │ └── main.go │ │ ├── reverseproxy2 │ │ └── main.go │ │ ├── ssh_conn.go │ │ └── ws_conn.go │ ├── ssh │ ├── cfgutil │ │ └── json.go │ ├── helper │ │ ├── config.json │ │ ├── main.go │ │ └── ssh.go │ └── main.go │ └── tcpforwarder │ ├── chiselwatcher │ ├── config.yaml │ └── main.go │ └── demo │ └── main.go ├── core ├── conf │ ├── conf.go │ └── t │ │ └── main.go ├── db │ ├── elasticsearch-official │ │ └── elasticsearch-official.go │ ├── elasticsearch │ │ └── elasticsearch.go │ ├── mongodb │ │ └── mongo.go │ ├── mysqldb │ │ └── mysql.go │ ├── pgsqldb │ │ └── pgsql.go │ └── redisdb │ │ └── redis.go ├── etcd │ └── etcd.go ├── http │ ├── paging │ │ └── paging.go │ └── ret │ │ ├── code.go │ │ ├── ctl │ │ └── controller.go │ │ └── svc │ │ └── server.go ├── logger │ ├── zap_with_lumberjack.go │ └── zap_with_lumberjack_test.go └── mq │ └── rabbitmq │ └── rabbitmq.go ├── data ├── conf │ ├── api │ │ ├── README.md │ │ ├── elasticsearch.yaml │ │ └── mongodb.yaml │ ├── config.yml │ ├── config_ip.yaml │ ├── data │ │ └── README.md │ └── filename.go └── data.go ├── demo ├── account │ ├── account.http │ ├── controller │ │ └── account.go │ ├── dto │ │ └── account.go │ ├── main.go │ ├── model │ │ └── account.go │ ├── repository │ │ └── account.go │ ├── router │ │ └── router.go │ └── server │ │ └── account.go ├── cmodel │ ├── common.go │ └── paging.go ├── common │ └── ret │ │ ├── code.go │ │ ├── ctl │ │ └── controller.go │ │ └── srv │ │ └── server.go ├── main.go ├── order │ ├── controller │ │ └── order.go │ ├── dto │ │ └── order.go │ ├── main.go │ ├── model │ │ └── order.go │ ├── order.http │ ├── repository │ │ └── order.go │ ├── router │ │ └── router.go │ └── server │ │ └── order.go ├── user │ ├── controller │ │ └── user.go │ ├── dto │ │ └── user.go │ ├── main.go │ ├── model │ │ └── model.go │ ├── repository │ │ └── user.go │ ├── router │ │ └── router.go │ ├── server │ │ └── user.go │ └── user.http └── validate │ ├── check.go │ └── check_test.go ├── desing-pattern ├── channel │ └── unbounded_channel.go ├── goadvanced │ ├── README.md │ ├── code.go │ ├── code_test.go │ ├── params.go │ ├── params_test.go │ ├── rand_test.go │ ├── revocer_test.go │ ├── slice.go │ └── slice_test.go ├── gobase │ ├── README.md │ ├── ast │ │ ├── example.go │ │ └── main.go │ ├── compiler │ │ ├── closure │ │ │ └── main.go │ │ ├── compiler_test.go │ │ ├── escape │ │ │ └── main.go │ │ ├── inline │ │ │ ├── inline.go │ │ │ └── inline_test.go │ │ └── ssa │ │ │ └── main.go │ └── floatingpoint │ │ └── main.go ├── goroutine-channel │ └── timeout.go ├── options │ └── options.go └── string │ └── intern.go ├── doc ├── compose │ ├── elasticsearch │ │ ├── cerebro.yml │ │ ├── es.yml │ │ └── kibana.yml │ ├── etcd-cluster.yml │ ├── etcd-single.yaml │ ├── mongod.conf │ ├── mongodb.yml │ ├── mysql.yml │ ├── postgressql.yml │ ├── rabbitmq.yml │ └── redis.yml └── istio │ ├── destination_rule.yaml │ ├── gateway.yaml │ ├── service_entry.yaml │ └── virtual_service.yaml ├── etcd ├── helloword │ └── hello.go └── lock │ ├── comment.md │ ├── etcdlock.go │ ├── etcdlock_test.go │ ├── mylock.go │ └── mylock_test.go ├── gin ├── graceful-restart │ ├── doc.go │ ├── endless │ │ └── main.go │ └── http │ │ └── main.go ├── helloworld │ └── main.go ├── middleware │ ├── auth.go │ ├── cros.go │ └── redirect.go ├── routers │ └── router.go ├── server │ └── user.go ├── simple │ └── router.go ├── swagger │ ├── Makefile │ ├── README.md │ ├── doc.go │ ├── docs │ │ ├── docs.go │ │ ├── swagger.json │ │ └── swagger.yaml │ ├── handle.go │ ├── main.go │ ├── ret │ │ └── ret.go │ └── swagger-auth.png ├── templates │ └── index.tmpl ├── user │ ├── gin_test.go │ ├── simple.go │ ├── userController.go │ └── userModel.go └── validator │ ├── custom.go │ ├── example │ ├── customfunc.go │ ├── i18n_zh.go │ ├── register.go │ └── server.go │ ├── hello │ └── hello.go │ ├── i18n.go │ ├── validate.go │ └── validate.http ├── git commit 规范.md ├── go-kit ├── hello │ ├── client │ │ ├── cmd │ │ │ └── client.go │ │ └── services │ │ │ ├── user_endpoint.go │ │ │ └── user_transport.go │ └── server │ │ ├── cmd │ │ └── server.go │ │ └── services │ │ ├── user_endpoint.go │ │ ├── user_service.go │ │ └── user_transport.go └── official │ ├── stringsvc1 │ ├── README.md │ ├── main.go │ └── stringsvc1.http │ ├── stringsvc2 │ ├── README.md │ ├── cmd.go │ ├── instrumentation.go │ ├── logging.go │ ├── server.go │ ├── stringsvc2.http │ └── transport.go │ └── stringsvc3 │ ├── README.md │ ├── cmd.go │ ├── instrumentation.go │ ├── logging.go │ ├── proxying.go │ ├── server.go │ ├── stringsvc3.http │ └── transport.go ├── go.mod ├── go.sum ├── gomock └── db │ ├── db.go │ ├── db_mock.go │ └── db_test.go ├── hack └── update-goimports.sh ├── http-client.env.json ├── ient ├── README.md ├── ent │ ├── client.go │ ├── ent.go │ ├── enttest │ │ └── enttest.go │ ├── hook │ │ └── hook.go │ ├── migrate │ │ ├── migrate.go │ │ └── schema.go │ ├── mutation.go │ ├── predicate │ │ └── predicate.go │ ├── runtime.go │ ├── runtime │ │ └── runtime.go │ ├── schema │ │ ├── base.go │ │ ├── common.go │ │ ├── mixin_keystone.go │ │ ├── mtime │ │ │ └── time.go │ │ ├── property │ │ │ └── user.go │ │ └── user.go │ ├── tx.go │ ├── user.go │ ├── user │ │ ├── user.go │ │ └── where.go │ ├── user_create.go │ ├── user_delete.go │ ├── user_query.go │ └── user_update.go └── main.go ├── image ├── assets │ └── origin.png ├── core │ ├── gray.go │ ├── gray_test.go │ ├── key.go │ ├── mosaic.go │ ├── mosaic_test.go │ ├── quality.go │ ├── quality_test.go │ ├── saturation.go │ └── saturation_test.go └── util │ ├── conv.go │ ├── io.go │ └── matrix.go ├── interview.md ├── interview └── question │ ├── 01-runtime.go │ └── question.go ├── kratos ├── Makefile ├── generate.go ├── google │ └── api │ │ ├── annotations.proto │ │ └── http.proto └── helloworld │ ├── hello_world.pb.go │ ├── hello_world.pb.gw.go │ ├── hello_world.proto │ └── hello_world_grpc.pb.go ├── lint.md ├── log ├── logrus │ ├── custom │ │ └── logrus.go │ ├── cutfile │ │ ├── cuthook.go │ │ └── logrus.go │ ├── hook │ │ ├── logrus.go │ │ └── simplehook.go │ └── simple │ │ └── logrus.go └── zap │ ├── custom │ └── zap_with_lumberjack.go │ ├── logger │ └── logger.go │ └── suagr │ └── suagr.go ├── mq ├── kafka │ ├── FAQ │ │ ├── FAQ.md │ │ ├── TODO.md │ │ ├── assets │ │ │ └── kafka-client-arch.png │ │ └── blog.md │ ├── config.go │ ├── demo │ │ ├── admin │ │ │ ├── cmd │ │ │ │ └── main.go │ │ │ ├── group.go │ │ │ └── topic.go │ │ ├── benchmark │ │ │ └── main.go │ │ ├── consumer │ │ │ ├── group │ │ │ │ ├── cmd │ │ │ │ │ └── main.go │ │ │ │ └── group_consumer.go │ │ │ └── standalone │ │ │ │ ├── cmd │ │ │ │ └── main.go │ │ │ │ └── standalone_consumer.go │ │ ├── offsetmanager │ │ │ ├── cmd │ │ │ │ └── main.go │ │ │ └── offsetmanager.go │ │ └── producer │ │ │ ├── async │ │ │ ├── async_producer.go │ │ │ └── cmd │ │ │ │ └── main.go │ │ │ └── sync │ │ │ ├── cmd │ │ │ └── main.go │ │ │ └── sync_producer.go │ ├── kafka.yaml │ ├── lesson │ │ ├── compression │ │ │ ├── cmd │ │ │ │ └── main.go │ │ │ └── compression.go │ │ ├── exactlyonce │ │ │ ├── cmd │ │ │ │ └── main.go │ │ │ └── exactlyonce.go │ │ └── partition │ │ │ ├── cmd │ │ │ └── main.go │ │ │ └── partition.go │ └── 名词表.md ├── nats │ ├── constant │ │ └── constant.go │ ├── nats │ │ ├── README.md │ │ ├── conn │ │ │ └── conn.go │ │ ├── msghandler │ │ │ └── print.go │ │ ├── nats-pub │ │ │ ├── pub.go │ │ │ └── pub_test.go │ │ ├── nats-sub │ │ │ ├── sub.go │ │ │ └── sub_test.go │ │ └── request-reply │ │ │ ├── reply.go │ │ │ ├── request.go │ │ │ └── request_test.go │ └── stan │ │ ├── README.md │ │ ├── conn │ │ └── conn.go │ │ ├── msghandler │ │ └── print.go │ │ ├── stan-pub │ │ ├── pub.go │ │ └── pub_test.go │ │ └── stan-sub │ │ ├── sub.go │ │ └── sub_test.go └── rabbitmq │ ├── confirm │ └── confirm.go │ ├── delay │ └── delay.go │ ├── demo │ └── stomp │ │ └── main.go │ ├── dlx │ └── dlx.go │ ├── durable │ └── durable.go │ ├── helloworld │ └── main.go │ ├── lazyqueue │ └── lazy.go │ ├── main │ └── main.go │ ├── priority │ └── priority.go │ ├── rabbitmq.go │ ├── second │ └── main.go │ ├── thrid │ └── thrid.go │ └── tx │ └── tx.go ├── other ├── cpucache │ ├── array.go │ └── array_test.go └── hash │ ├── hash.go │ └── hash_test.go ├── shell ├── bot.sh ├── comom.sh ├── doc.go ├── docker-clear.sh ├── docker.sh ├── install-chisel.sh ├── install-docker-compose.sh ├── install-docker-ubuntu.sh ├── install-docker.sh ├── install-ffmpeg.sh ├── install-go.sh ├── install-nfs.sh ├── install-nodejs.sh ├── install-openssl.sh ├── install-python.sh ├── iptables-log-off.sh ├── iptables-log-on.sh ├── kernel-upgrage.sh ├── lesson │ ├── find.md │ ├── makefile.md │ ├── read.md │ ├── while.md │ ├── 变量默认值.md │ ├── 布尔运算.md │ └── 数值运算.md ├── load.sh ├── loop.sh ├── memory-free.sh ├── memory-malloc.c ├── mongologrotate.sh ├── mount-cgroup.sh ├── oom_score.sh └── podpid.sh ├── storage ├── elasticsearch │ ├── crud │ │ ├── hello.go │ │ └── hello_init.go │ ├── elastic │ │ └── elastic.go │ ├── official │ │ └── official.go │ └── search │ │ ├── key.go │ │ ├── site.go │ │ └── site_test.go ├── mongodb │ ├── first │ │ └── first.go │ ├── model │ │ └── dmeo.go │ └── repository │ │ └── demo.go ├── mysql │ ├── gorm │ │ ├── crud │ │ │ └── main.go │ │ └── model │ │ │ └── user.go │ └── mysql.go ├── postgresql │ ├── constant │ │ └── constant.go │ ├── crud │ │ └── crud.go │ ├── relations │ │ ├── belongs_to │ │ │ └── belong_to.go │ │ ├── has_many │ │ │ └── has_many.go │ │ ├── has_one │ │ │ └── has_one.go │ │ └── many2many │ │ │ └── many2many.go │ └── util │ │ └── handerror.go └── redis │ ├── bloomfiler_custom.go │ ├── bloomfilter_custom_test.go │ ├── bloomfilter_offical.go │ ├── cache-cross.go │ ├── hash │ ├── bloomhash.go │ └── bloomhash_test.go │ ├── lock │ ├── fake.go │ └── redis.go │ ├── redis.go │ └── redis_test.go ├── test.http ├── test ├── gc │ ├── gc.go │ └── pass_array_test.go ├── map │ ├── m.go │ ├── m_test.go │ └── smap.go ├── maps │ ├── concurrent_map_benchmark_adapter.go │ ├── map_benchmark_test.go │ ├── rw_map.go │ └── sync_map_benchmark_adapter.go ├── mock │ ├── mock_user.go │ ├── user.go │ └── user_test.go ├── pprof │ ├── auto-pprof │ │ └── main.go │ ├── continuous-profiling │ │ ├── main.go │ │ └── main_test.go │ ├── server │ │ └── server.go │ └── tool │ │ └── tool.go ├── slice │ ├── slice.go │ └── slice_test.go ├── string_concat │ └── concat_string_test.go └── unittest │ ├── 01-sum.go │ ├── 01-sum_test.go │ ├── doc.go │ └── lock_test.go ├── tips ├── filter │ ├── filter.go │ ├── split_filter.go │ ├── straight_piple.go │ ├── straight_piple_test.go │ ├── sum_filter.go │ └── to_int_filter.go └── microkernel │ ├── agent.go │ └── agent_test.go ├── tmpl └── main.go ├── tools ├── cron.go ├── jwt │ ├── jwt.go │ └── jwt_test.go ├── lock │ ├── interface.go │ └── redis.go ├── pay │ ├── README.md │ ├── alipay.go │ └── wxpay.go ├── pool │ ├── README.md │ ├── channel │ │ ├── channel.go │ │ └── channel_test.go │ ├── conn.go │ ├── list.go │ ├── list_test.go │ ├── pool.go │ └── slice │ │ ├── slice.go │ │ └── slice_test.go ├── region │ ├── README.md │ ├── core │ │ ├── geo.go │ │ ├── geo_test.go │ │ └── region.go │ ├── http │ │ ├── cmd │ │ │ ├── ip.http │ │ │ └── region.go │ │ ├── controller │ │ │ ├── geo.go │ │ │ └── region.go │ │ └── router │ │ │ └── router.go │ ├── rpc │ │ ├── client │ │ │ └── main.go │ │ ├── proto │ │ │ ├── make.cmd │ │ │ ├── region.pb.go │ │ │ ├── region.proto │ │ │ └── region_grpc.pb.go │ │ └── server │ │ │ └── main.go │ └── util │ │ ├── distance.go │ │ └── distance_test.go ├── sensitive │ ├── dfa │ │ ├── dfa.go │ │ └── dfa_test.go │ └── doc.go ├── similar │ └── frechet │ │ ├── frechet.go │ │ └── frechet_test.go ├── sitemap │ ├── generator.go │ └── generator_test.go └── weights │ ├── weights.go │ └── weights_test.go ├── training ├── README.md ├── availability │ └── a.go ├── comment │ └── singleflight.go ├── engineering │ ├── api │ │ ├── design.proto │ │ ├── dial.go │ │ └── error_code.go │ ├── dip.go │ └── wire │ │ ├── main.go │ │ ├── wire.go │ │ └── wire_gen.go ├── error │ ├── error.go │ ├── handler.go │ ├── pgkerrors.go │ ├── recommend.go │ └── wrap.go ├── goroutine │ ├── 1.go │ ├── 2.go │ ├── 3.go │ ├── 4.go │ └── trace.go ├── memory-model │ ├── a.html │ └── reordering.go ├── network │ └── demo │ │ ├── tcp │ │ └── main.go │ │ └── udp │ │ └── main.go ├── package-context │ └── withvalue.go ├── package-sync │ ├── 1-compilation.go │ ├── 2-interface.go │ ├── 3-atomic.go │ ├── 4-mutex-1.go │ └── err_group.go └── runtime │ ├── goroutine │ └── scheduler.go │ └── memory │ └── escape.go └── utils ├── base64.go ├── bloom ├── bloom_filter.go └── bloom_filter_test.go ├── compress ├── gzip.go └── gzip_test.go ├── container-test ├── cmd │ └── main.go ├── container_test.go └── redis_test.go ├── convert ├── bytes_string.go ├── bytes_string_test.go ├── struct2map.go └── struct2map_test.go ├── crypto ├── aes │ ├── aes_cbc.go │ ├── aes_cbc_test.go │ ├── aes_cfb.go │ ├── aes_ecb.go │ └── aes_ecb_test.go └── crypto.go ├── file.go ├── file_test.go ├── glimit ├── glimiter.go └── glimiter_test.go ├── gopsutil └── main.go ├── hotrank ├── hotrank.go └── hotrank_test.go ├── html.go ├── html_test.go ├── httputil ├── http.go └── http_test.go ├── ip ├── ip.go └── ip_test.go ├── itime ├── time.go └── time_test.go ├── libs.md ├── ratelimit ├── aegis.go ├── aegis_test.go ├── doc.go ├── leaky_bucket.go ├── leaky_bucket_test.go ├── simple_count.go ├── simple_count_test.go ├── token_bucket.go └── token_bucket_test.go ├── runtime.go ├── snowflake ├── mist.go └── snowflake_test.go ├── string.go └── string_test.go /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .idea -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; https://editorconfig.org/ 2 | 3 | root = true 4 | 5 | [*] 6 | insert_final_newline = true 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | indent_style = space 10 | indent_size = 2 11 | 12 | [{Makefile,go.mod,go.sum,*.go,.gitmodules}] 13 | indent_style = tab 14 | indent_size = 4 15 | 16 | [*.md] 17 | indent_size = 4 18 | trim_trailing_whitespace = false 19 | 20 | [{*.Dockerfile,Dockerfile}] 21 | indent_size = 4 22 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # We'll let Git's auto-detection algorithm infer if a file is text. If it is, 2 | # enforce LF line endings regardless of OS or git configurations. 3 | * text=auto eol=lf 4 | 5 | # Isolate binary files in case the auto-detection algorithm fails and 6 | # marks them as text files (which could brick them). 7 | *.{png,jpg,jpeg,gif,webp,woff,woff2} binary -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/actions/starter-workflows 2 | name: Go 3 | on: 4 | push: 5 | branches: [ $default-branch ] 6 | pull_request: 7 | branches: [ $default-branch ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | 15 | - name: Set up Go 16 | uses: actions/setup-go@v3 17 | with: 18 | go-version: 1.18 19 | 20 | - name: Build 21 | run: go build -v ./... 22 | 23 | - name: Test 24 | run: go test -v ./... 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ip2region.db 4 | *.dll 5 | *.so 6 | *.dylib 7 | **/*.idea 8 | # Test binary, build with `go test -c` 9 | *.test 10 | .DS_Store 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | *.log 15 | .idea 16 | /wbl/ 17 | # ip2geo 数据库 18 | *.mmdb 19 | # ip2region 数据库 20 | *.db 21 | /dist 22 | -------------------------------------------------------------------------------- /17x/c/worker.c: -------------------------------------------------------------------------------- 1 | int counter = 0; 2 | void *worker() { 3 | for (int i=0;i<10;i++) { 4 | counter++; 5 | } 6 | return NULL; 7 | } 8 | 9 | int main(int argc, char *argv[]) { 10 | worker(); 11 | } -------------------------------------------------------------------------------- /17x/exec/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "os/exec" 6 | "syscall" 7 | ) 8 | 9 | func main() { 10 | 11 | binary, lookErr := exec.LookPath("git") 12 | if lookErr != nil { 13 | panic(lookErr) 14 | } 15 | 16 | // args := []string{"ls", "-a", "-l", "-h"} 17 | args := []string{"git", "-v"} 18 | 19 | env := os.Environ() 20 | 21 | execErr := syscall.Exec(binary, args, env) 22 | if execErr != nil { 23 | panic(execErr) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /17x/html/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | ) 8 | 9 | func main() { 10 | r := "https://vaptcha.com/a/b/c/d/e/f" 11 | parse, err := url.Parse(r) 12 | if err != nil { 13 | return 14 | } 15 | parse2, err := url.Parse("./xxx.html") 16 | if err != nil { 17 | log.Println("err:", err) 18 | } 19 | reference := parse.ResolveReference(parse2) 20 | fmt.Println(reference) 21 | } 22 | -------------------------------------------------------------------------------- /17x/ient/ent/generate.go: -------------------------------------------------------------------------------- 1 | package ent 2 | 3 | //go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema 4 | -------------------------------------------------------------------------------- /17x/ient/ent/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package predicate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | ) 8 | 9 | // User is the predicate function for user builders. 10 | type User func(*sql.Selector) 11 | -------------------------------------------------------------------------------- /17x/ient/ent/runtime/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package runtime 4 | 5 | // The schema-stitching logic is generated in i-go/17x/ient/ent/runtime.go 6 | 7 | const ( 8 | Version = "v0.10.1" // Version of ent codegen. 9 | Sum = "h1:dM5h4Zk6yHGIgw4dCqVzGw3nWgpGYJiV4/kyHEF6PFo=" // Sum of ent codegen. 10 | ) 11 | -------------------------------------------------------------------------------- /17x/ient/ent/schema/user.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/schema/field" 6 | ) 7 | 8 | // User holds the schema definition for the User entity. 9 | type User struct { 10 | ent.Schema 11 | } 12 | 13 | // Fields of the User. 14 | func (User) Fields() []ent.Field { 15 | return []ent.Field{ 16 | field.Int("age").Positive(), 17 | field.String("name").Default("unknown"), 18 | } 19 | } 20 | 21 | // Edges of the User. 22 | func (User) Edges() []ent.Edge { 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /17x/leetcode/common.go: -------------------------------------------------------------------------------- 1 | package leetcode 2 | 3 | // ListNode Definition for singly-linked list. 4 | type ListNode struct { 5 | Val int 6 | Next *ListNode 7 | } 8 | -------------------------------------------------------------------------------- /17x/painkiller/pill.go: -------------------------------------------------------------------------------- 1 | // pill.go 2 | package painkiller 3 | 4 | // stringer并不是 Go 自带的工具,需要手动安装。可以执行下面的命令安装:go get golang.org/x/tools/cmd/stringer 5 | 6 | //go:generate stringer -type=Pill 7 | type Pill int 8 | 9 | const ( 10 | Placebo Pill = iota 11 | Aspirin 12 | Ibuprofen 13 | Paracetamol 14 | Acetaminophen = Paracetamol 15 | ) 16 | -------------------------------------------------------------------------------- /17x/test/lb/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | ) 7 | 8 | func main() { 9 | svc := []Server{"s1", "s2", "s3"} 10 | lb := NewLBRand(svc) 11 | for i := 0; i < 10; i++ { 12 | s := lb() 13 | fmt.Println(s) 14 | } 15 | } 16 | 17 | type Server string 18 | type LB func() Server 19 | 20 | func NewLB(svc []Server) LB { 21 | var i int 22 | return func() Server { 23 | i++ 24 | if i >= len(svc) { 25 | i = 0 26 | } 27 | return svc[i] 28 | } 29 | } 30 | 31 | func NewLBRand(svc []Server) LB { 32 | return func() Server { 33 | return svc[rand.Int63()%int64(len(svc))] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /17x/test/selfrewrite.go: -------------------------------------------------------------------------------- 1 | /* Go quine */ 2 | package main 3 | 4 | import "fmt" 5 | 6 | func main() { 7 | fmt.Printf("%s%c%s%c\n", q, 0x60, q, 0x60) 8 | } 9 | 10 | var q = `/* Go quine */ 11 | package main 12 | import "fmt" 13 | func main() { 14 | fmt.Printf("%s%c%s%c\n", q, 0x60, q, 0x60) 15 | } 16 | var q = ` 17 | -------------------------------------------------------------------------------- /17x/test/t/t_test.go: -------------------------------------------------------------------------------- 1 | package t 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | func BenchmarkName(b *testing.B) { 9 | var s sync.Map 10 | s.Store("foo", "bar") 11 | b.ResetTimer() 12 | for i := 0; i < b.N; i++ { 13 | s.LoadOrStore("foo", "bar") 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /17x/trace.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "runtime/trace" 7 | ) 8 | 9 | // go run trace.go 生成 trace.out 10 | // go tool trace trace.out 分析 trace.out 文件 11 | func main() { 12 | 13 | // 创建trace文件 14 | f, err := os.Create("trace.out") 15 | if err != nil { 16 | panic(err) 17 | } 18 | defer f.Close() 19 | 20 | // 启动trace goroutine 21 | err = trace.Start(f) 22 | if err != nil { 23 | panic(err) 24 | } 25 | defer trace.Stop() 26 | 27 | // main 28 | fmt.Println("Hello World") 29 | } 30 | -------------------------------------------------------------------------------- /7days/orm/dialect/dialect.go: -------------------------------------------------------------------------------- 1 | package dialect 2 | 3 | import "reflect" 4 | 5 | var dialectsMap = map[string]Dialect{} 6 | 7 | // Dialect 方言 用于适配不同数据库 8 | type Dialect interface { 9 | DataTypeOf(typ reflect.Value) string 10 | TableExistSQL(tableName string) (string, []interface{}) 11 | } 12 | 13 | func RegisterDialect(name string, dialect Dialect) { 14 | dialectsMap[name] = dialect 15 | } 16 | 17 | func GetDialect(name string) (dialect Dialect, ok bool) { 18 | dialect, ok = dialectsMap[name] 19 | return 20 | } 21 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 编译环境 2 | FROM golang:1.14 as build 3 | ENV GOPROXY=https://goproxy.cn GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=amd64 4 | WORKDIR /i-go 5 | COPY . /i-go 6 | # -ldflags="-s -w" 减小二进制文件体积 https://golang.org/cmd/link/#hdr-Command_Line 7 | RUN go build -ldflags="-s -w" -o main ./server/api/api.go 8 | 9 | # 运行环境 10 | FROM alpine:latest 11 | WORKDIR /root 12 | # 时区信息 13 | COPY --from=build /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 14 | # 二进制文件 15 | COPY --from=build /i-go/main . 16 | # 配置文件 17 | COPY ./conf/config.yaml /root/conf/ 18 | ENTRYPOINT ["./main"] 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # i-go 2 | golang learning 3 | 4 | 5 | 6 | Thanks 7 | *** 8 | [![JetBrains](./assets/jetbrains-variant.svg)](https://www.jetbrains.com/?from=i-go) 9 | -------------------------------------------------------------------------------- /a-tutorials/advanced/04-map/map.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | map1() 7 | } 8 | 9 | func map1() { 10 | // 字面量初始化 11 | h1 := map[string]string{ 12 | "k1": "v1", 13 | "k2": "v2", 14 | "k3": "v3", 15 | } 16 | fmt.Println(h1) 17 | // 运行时初始化 18 | h2 := make(map[string]string) 19 | h2["k1"] = "v1" 20 | h2["k2"] = "v2" 21 | h2["k3"] = "v3" 22 | } 23 | 24 | type B struct { 25 | ID string 26 | } 27 | -------------------------------------------------------------------------------- /a-tutorials/advanced/09-panic-recover/panic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func A() { 6 | defer A1() 7 | defer A2() 8 | panic("panic A") 9 | } 10 | 11 | func A1() { 12 | defer func() { 13 | fmt.Println("recover A1") 14 | defer func() { 15 | fmt.Println("recover A2") 16 | recover() 17 | }() 18 | recover() 19 | panic("Panic A2") 20 | }() 21 | panic("panic A1") 22 | } 23 | func A2() { 24 | 25 | } 26 | 27 | func main() { 28 | A() 29 | } 30 | -------------------------------------------------------------------------------- /a-tutorials/advanced/11-interface/17x.txt: -------------------------------------------------------------------------------- 1 | lixueduan.com 2 | refersmoon.com -------------------------------------------------------------------------------- /a-tutorials/advanced/12-type-assert/17x.txt: -------------------------------------------------------------------------------- 1 | lixueduan.com 2 | refersmoon.com -------------------------------------------------------------------------------- /a-tutorials/advanced/benchmark/forrange/unit_test.go: -------------------------------------------------------------------------------- 1 | package forrange 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestUnit(t *testing.T) { 9 | in := []interface{}{"A"} 10 | inte := interface{}(in) 11 | aa := inte.([]interface{}) 12 | fmt.Println(aa) 13 | for _, v := range in { 14 | tmp, ok := v.(string) 15 | if !ok { 16 | fmt.Println("断言失败") 17 | } 18 | fmt.Println(tmp) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /a-tutorials/advanced/rand/rand.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | ) 7 | 8 | // 正确使用姿势:程序启动时初始化设定一次随机种子即可,比如直接把当前纳秒时间戳当做随机数种子。 9 | func main() { 10 | // randOne() 11 | randTwo() 12 | // randThree() 13 | } 14 | 15 | func randOne() { 16 | for i := 0; i < 10; i++ { 17 | fmt.Print(rand.Intn(10)) // 每轮10个随机数都是按照 1779185060 这个顺序出现 18 | } 19 | } 20 | func randTwo() { 21 | rand.Seed(10) 22 | for i := 0; i < 20; i++ { 23 | fmt.Print(rand.Intn(10)) // 每轮10个随机数都是按照 4879849558 这个顺序出现 24 | } 25 | } 26 | func randThree() { 27 | for i := 0; i < 10; i++ { 28 | rand.Seed(10) 29 | fmt.Print(rand.Intn(10)) // 每次随机值都为4 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /a-tutorials/base/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | go dev 官网:https://go.dev/learn/ 4 | 5 | 一些简单的例子 :https://gobyexample.com/ 6 | 7 | golang 上手GORM V2 + Opentracing链路追踪优化CRUD体验(源码阅读): 8 | https://github.com/avtion/gormTracing 9 | GORM V2 踩坑: 10 | https://www.cnblogs.com/rickiyang/p/14517120.html 11 | -------------------------------------------------------------------------------- /a-tutorials/base/channel/once.go: -------------------------------------------------------------------------------- 1 | package channel 2 | 3 | type Once chan struct{} 4 | 5 | func NewOnce() Once { 6 | o := make(Once, 1) 7 | o <- struct{}{} 8 | return o 9 | } 10 | 11 | func (o Once) Do(f func()) { 12 | _, ok := <-o 13 | if !ok { 14 | return 15 | } 16 | f() 17 | close(o) 18 | } 19 | -------------------------------------------------------------------------------- /a-tutorials/base/channel/os_test.go: -------------------------------------------------------------------------------- 1 | package channel 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | "testing" 7 | ) 8 | 9 | func TestMain(m *testing.M) { 10 | fmt.Println("before") 11 | m.Run() 12 | fmt.Println("after") 13 | } 14 | 15 | func TestA(t *testing.T) { 16 | // rawUrl := "https://www.douban.com/accounts/connect/wechat/callback" 17 | rawUrl := "https://www.puug.com?url=https://www.puug.com" 18 | escape := url.QueryEscape(rawUrl) 19 | fmt.Println(escape) 20 | } 21 | 22 | func TestB(t *testing.T) { 23 | fmt.Println("B") 24 | } 25 | -------------------------------------------------------------------------------- /a-tutorials/base/channel/semaphore.go: -------------------------------------------------------------------------------- 1 | package channel 2 | 3 | type Semaphore chan struct{} 4 | 5 | func NewSemaphore(size int) Semaphore { 6 | return make(Semaphore, size) 7 | } 8 | 9 | func (s Semaphore) Lock() { 10 | s <- struct{}{} 11 | } 12 | 13 | func (s Semaphore) Unlock() { 14 | <-s 15 | } 16 | -------------------------------------------------------------------------------- /a-tutorials/base/http/01_http.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | func HelloServer(w http.ResponseWriter, r *http.Request) { 10 | _, err := io.WriteString(w, "Hello,World \n") 11 | if err != nil { 12 | log.Println(err) 13 | } 14 | } 15 | 16 | func main() { 17 | http.HandleFunc("/hello", HelloServer) 18 | err := http.ListenAndServe(":50051", nil) 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /a-tutorials/base/http/03_http_pprof.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log" 6 | "net/http" 7 | _ "net/http/pprof" 8 | ) 9 | 10 | func HelloServerPprof(w http.ResponseWriter, r *http.Request) { 11 | _, err := io.WriteString(w, "Hello,World \n") 12 | if err != nil { 13 | log.Println(err) 14 | } 15 | } 16 | 17 | func main() { 18 | // pprof 19 | go func() { 20 | _ = http.ListenAndServe("0.0.0.0:8180", nil) 21 | }() 22 | http.HandleFunc("/hello", HelloServerPprof) 23 | err := http.ListenAndServe(":50051", nil) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /a-tutorials/base/io/io_interface.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | ) 8 | 9 | func main() { 10 | readWriter() 11 | } 12 | 13 | func readWriter() { 14 | reader := bufio.NewReaderSize(bytes.NewReader([]byte("hello word")), 20) 15 | // peek 读取后 并不会修改 已读计数 16 | peek, err := reader.Peek(5) 17 | if err != nil { 18 | fmt.Println(err) 19 | } 20 | fmt.Println(string(peek)) 21 | fmt.Printf("%#v \n", reader) 22 | t := make([]byte, 10) 23 | _, err = reader.Read(t) 24 | if err != nil { 25 | fmt.Println(err) 26 | } 27 | fmt.Println(string(t)) 28 | fmt.Printf("%#v \n", reader) 29 | } 30 | -------------------------------------------------------------------------------- /a-tutorials/base/io/os.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "syscall" 7 | ) 8 | 9 | func main() { 10 | file() 11 | } 12 | 13 | func file() { 14 | f, err := os.Create("t.txt") 15 | if err != nil { 16 | fmt.Println(err) 17 | } 18 | fmt.Printf("%#v \n", f) 19 | // NewFile 并不是创建文件 而是包装成 File 20 | // 这里将 标准错误输出 包装成一个 File 21 | stderr := os.NewFile(uintptr(syscall.Stderr), "/dev/stderr") 22 | if stderr != nil { 23 | defer stderr.Close() 24 | _, _ = stderr.WriteString( 25 | "The Go language program writes the contents into stderr.\n") 26 | } 27 | // 1st: 文件名 2nd: 操作模式 3rd: 权限模式 28 | os.OpenFile("t.txt", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) 29 | } 30 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/advance/unsafe.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func main() { 9 | unsafe1() 10 | } 11 | 12 | func unsafe1() { 13 | var i int = 1 14 | f := *(*float64)(unsafe.Pointer(&i)) 15 | fmt.Println(unsafe.Pointer(&i)) 16 | fmt.Println(f) 17 | } 18 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/factory/model/person.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "fmt" 4 | 5 | type person struct { 6 | name string 7 | salary float64 8 | } 9 | 10 | func NewPerson(name string, salary float64) *person { 11 | return &person{name, salary} 12 | } 13 | 14 | func (person *person) GetName() string { 15 | return person.name 16 | } 17 | func (person *person) SetName(name string) { 18 | person.name = name 19 | } 20 | func (person *person) GetSalary() float64 { 21 | return person.salary 22 | } 23 | func (person *person) SetSalary(salary float64) { 24 | if salary > 0 { 25 | person.salary = salary 26 | } else { 27 | fmt.Println("Salary 范围不正确...") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/factory/model/student.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type student struct { 4 | Name string 5 | age int 6 | } 7 | 8 | type pupil struct { 9 | student 10 | } 11 | 12 | // student首字母小写后 是私有的 只能在 model 包使用 13 | // 使用工厂模式来解决 14 | func NewStudent(name string, age int) *student { 15 | return &student{name, age} 16 | } 17 | 18 | // 如果字段是私有的 也可以提供一个获取字段的方法 类似Java中的Get方法 19 | func (student *student) GetAge() int { 20 | return student.age 21 | } 22 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/simple/01-hello/hello.go: -------------------------------------------------------------------------------- 1 | package _1_hello 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "path/filepath" 8 | ) 9 | 10 | func main() { 11 | fmt.Println("Hello World~") 12 | } 13 | 14 | // path 获取可执行文件路径 15 | func path() string { 16 | path, _ := exec.LookPath(os.Args[0]) 17 | s, _ := filepath.Abs(path) 18 | return s 19 | } 20 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/simple/02-datastructure/quote/channel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | var MyChannel chan int = make(chan int, 10) 8 | var EndChan chan int = make(chan int, 10) 9 | 10 | func send(ch chan int) { 11 | for i := 0; i < 10; i++ { 12 | ch <- i 13 | fmt.Println("Send ", i) 14 | } 15 | } 16 | func recv(ch chan int) { 17 | for i := 0; i < 10; i++ { 18 | res := <-ch 19 | EndChan <- res 20 | fmt.Println("Recv ", res) 21 | } 22 | } 23 | 24 | func main() { 25 | go send(MyChannel) 26 | go recv(MyChannel) 27 | for i := 0; i < 10; i++ { 28 | <-EndChan 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/simple/06-function/params.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // 不定参 6 | func main() { 7 | iSum := addSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 8 | fmt.Println(iSum) 9 | } 10 | 11 | //不定参数 其实是一个切片 12 | func addSum(data ...int) int { 13 | fmt.Printf("%T \n", data) 14 | result := 0 15 | for _, value := range data { 16 | result += value 17 | } 18 | return result 19 | } 20 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/simple/06-function/recursive.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // 递归 6 | func main() { 7 | var i int 8 | for i = 0; i < 10; i++ { 9 | fmt.Printf("%d\n", fibonaci(i)) 10 | } 11 | } 12 | 13 | func fibonaci(i int) int { 14 | if i < 0 { 15 | panic("invalid i") 16 | } 17 | if i == 0 { 18 | return 0 19 | } 20 | if i == 1 { 21 | return 1 22 | } 23 | return fibonaci(i-1) + fibonaci(i-2) 24 | } 25 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/simple/08_interface/faq.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type People interface { 6 | Speak(string) string 7 | } 8 | 9 | type Student struct{} 10 | 11 | func (stu *Student) Speak(think string) (talk string) { 12 | if think == "sb" { 13 | talk = "你是个大帅比" 14 | } else { 15 | talk = "您好" 16 | } 17 | return 18 | } 19 | 20 | func main() { 21 | var s = Student{} 22 | // Speak 方法接收者为 *Student 所以只有 Student的指针才算实现了 People接口 23 | var peo People = &s 24 | think := "bitch" 25 | fmt.Println(peo.Speak(think)) 26 | } 27 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/simple/09_others/automic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync/atomic" 6 | ) 7 | 8 | func main() { 9 | value := atomic.Value{} 10 | value.Store("x") 11 | x := value.Load() 12 | fmt.Println(x) 13 | } 14 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/simple/09_others/defer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | for i := 0; i < 3; i++ { 7 | /* defer func(v int) { 8 | fmt.Println(v) 9 | }(i)*/ 10 | defer func() { 11 | fmt.Println(i + 1) 12 | }() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/simple/09_others/err.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | simpleErr() 9 | } 10 | 11 | func simpleErr() { 12 | errorf := fmt.Errorf("X:%v ", "s") 13 | fmt.Println(errorf) 14 | } 15 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/simple/09_others/http.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func myfunc(w http.ResponseWriter, r *http.Request) { 9 | fmt.Fprintf(w, "hi") 10 | } 11 | 12 | func main() { 13 | http.HandleFunc("/", myfunc) 14 | http.ListenAndServe(":8080", nil) 15 | } 16 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/simple/09_others/json.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | u1 := User3{"illusory", 22} 10 | uJson, e := json.Marshal(u1) 11 | if e != nil { 12 | fmt.Println("err:", e) 13 | } 14 | fmt.Println(string(uJson)) 15 | var u2 User3 16 | e = json.Unmarshal([]byte(uJson), &u2) 17 | if e != nil { 18 | fmt.Println("err:", e) 19 | } 20 | 21 | fmt.Println(u2) 22 | 23 | } 24 | 25 | type User3 struct { 26 | Name string `json:"name"` 27 | Age int `json:"age"` 28 | } 29 | -------------------------------------------------------------------------------- /a-tutorials/base/lessons/simple/dmeo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //#include 4 | import ( 5 | "C" 6 | ) 7 | 8 | func main() { 9 | C.puts(C.CString("hello world\n")) 10 | } 11 | -------------------------------------------------------------------------------- /a-tutorials/base/mypprof/trace/trace.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "runtime/trace" 7 | ) 8 | 9 | func main() { 10 | 11 | //创建trace文件 12 | f, err := os.Create("trace.out") 13 | if err != nil { 14 | panic(err) 15 | } 16 | 17 | defer f.Close() 18 | 19 | //启动trace goroutine 20 | err = trace.Start(f) 21 | if err != nil { 22 | panic(err) 23 | } 24 | defer trace.Stop() 25 | 26 | //main 27 | fmt.Println("Hello World") 28 | } 29 | -------------------------------------------------------------------------------- /a-tutorials/base/mytesttt/fib.go: -------------------------------------------------------------------------------- 1 | package mytesttt 2 | 3 | func Fib(n int) int { 4 | if n < 2 { 5 | return n 6 | } 7 | return Fib(n-1) + Fib(n-2) 8 | } 9 | -------------------------------------------------------------------------------- /a-tutorials/base/second_lession/network/http/01-http.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | func main() { 8 | http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) { 9 | _, _ = writer.Write([]byte("Hello,World")) 10 | }) 11 | err := http.ListenAndServe(":8079", nil) 12 | if err != nil { 13 | panic(err) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /a-tutorials/base/second_lession/network/http/02-http-custom.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) { 10 | _, _ = writer.Write([]byte("Hello,World")) 11 | }) 12 | m := http.NewServeMux() 13 | srv := &http.Server{ 14 | Addr: ":8079", 15 | Handler: m, 16 | ReadTimeout: 3 * time.Second, 17 | WriteTimeout: 3 * time.Second, 18 | } 19 | err := srv.ListenAndServe() 20 | if err != nil { 21 | panic(err) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /a-tutorials/base/second_lession/network/net/net.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "strings" 7 | ) 8 | 9 | func NetworkInterface() { 10 | interfaces, err := net.Interfaces() 11 | if err != nil { 12 | fmt.Println("err:", err) 13 | return 14 | } 15 | for _, v := range interfaces { 16 | fmt.Println(v) 17 | } 18 | fmt.Println(strings.Repeat("~", 20)) 19 | names, err := net.LookupAddr("192.168.0.1") 20 | if err != nil { 21 | fmt.Println("err:", err) 22 | return 23 | } 24 | for _, v := range names { 25 | fmt.Println(v) 26 | } 27 | fmt.Println(strings.Repeat("~", 20)) 28 | 29 | } 30 | -------------------------------------------------------------------------------- /a-tutorials/base/second_lession/network/net/socket/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | ) 7 | 8 | func main() { 9 | conn, err := net.Dial("tcp", "localhost:9800") 10 | if err != nil { 11 | panic(err) 12 | } 13 | defer conn.Close() 14 | var data string 15 | _, err = fmt.Scan(&data) 16 | _, err = conn.Write([]byte(data)) 17 | if err != nil { 18 | 19 | } 20 | buffer := make([]byte, 2048) 21 | var n int 22 | for { 23 | n, _ := conn.Read(buffer) 24 | if n != 0 { 25 | break 26 | } 27 | } 28 | fmt.Println(conn.RemoteAddr().String(), "read data string:\n", string(buffer[:n])) 29 | } 30 | -------------------------------------------------------------------------------- /a-tutorials/base/sync/map.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "unicode/utf8" 7 | ) 8 | 9 | func main() { 10 | // helloMap() 11 | fmt.Println("Hello, 世界", len("世界"), utf8.RuneCountInString("世界")) 12 | } 13 | 14 | // https://www.jianshu.com/p/5bbe3a1cea61 15 | func helloMap() { 16 | m := sync.Map{} 17 | m.Store("key", "value") 18 | load, ok := m.Load("key") 19 | if ok { 20 | fmt.Println(load) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /a-tutorials/base/sync/mutex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var x = 0 9 | 10 | func increment(wg *sync.WaitGroup, m *sync.Mutex) { 11 | m.Lock() 12 | defer func() { 13 | m.Unlock() 14 | wg.Done() 15 | }() 16 | // 由于加锁了 所以同时只会有一个goroutine在执行这段代码 17 | // 不会出现值丢失的问题 18 | x = x + 1 19 | } 20 | 21 | func main() { 22 | var w sync.WaitGroup 23 | var m sync.Mutex 24 | for i := 0; i < 1000; i++ { 25 | w.Add(1) 26 | // 1000个goroutine并发修改x的值 27 | go increment(&w, &m) 28 | } 29 | w.Wait() 30 | fmt.Println("final value of x", x) 31 | } 32 | -------------------------------------------------------------------------------- /a-tutorials/base/sync/pm2.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps": [ 3 | { 4 | "name": "puug-pc", 5 | "max_memory_restart": "1G", 6 | "script": "server/index.js", 7 | "env": { 8 | "NODE_ENV": "production", 9 | "PORT": 3000, 10 | "HOST": "localhost" 11 | }, 12 | "instances": 0, 13 | "exec_mode": "cluster", 14 | "autorestart": true, 15 | "watch": true, 16 | "error_file":"./logs/error.log", 17 | "out_file":"./logs/out.log", 18 | "pid_file": "./.pm2/pid/app-pm_id.pid" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /a-tutorials/base/sync/waitgroup.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | // New一个waitGroup 11 | waitGroup := sync.WaitGroup{} 12 | // add 2 表示有两个需要等待 13 | waitGroup.Add(2) 14 | for i := 0; i < 2; i++ { 15 | go func(i int) { 16 | fmt.Print(i) 17 | time.Sleep(time.Second) 18 | // 执行完成后done一个 19 | defer waitGroup.Done() 20 | }(i) 21 | } 22 | // 程序会阻塞直到计数器减为零 23 | waitGroup.Wait() 24 | } 25 | -------------------------------------------------------------------------------- /a-tutorials/base/t/recover.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/signal" 7 | "syscall" 8 | ) 9 | 10 | func main() { 11 | 12 | sigs := make(chan os.Signal, 1) 13 | 14 | signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) 15 | 16 | done := make(chan bool, 1) 17 | 18 | go func() { 19 | 20 | sig := <-sigs 21 | fmt.Println() 22 | fmt.Println(sig) 23 | done <- true 24 | }() 25 | 26 | fmt.Println("awaiting signal") 27 | <-done 28 | fmt.Println("exiting") 29 | } 30 | -------------------------------------------------------------------------------- /algorithm/agc/recursion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Recursion(n int) int { 6 | if n == 0 { 7 | return 1 8 | } 9 | 10 | return n * Recursion(n-1) 11 | } 12 | 13 | func main() { 14 | fmt.Println(Recursion(5)) 15 | } 16 | -------------------------------------------------------------------------------- /algorithm/agc/tower/tower.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var total = 0 6 | 7 | // 汉诺塔 8 | // 一开始A杆上有N个盘子,B和C杆都没有盘子。 9 | func main() { 10 | n := 30 // 64 个盘子 11 | a := "a" // 杆子A 12 | b := "b" // 杆子B 13 | c := "c" // 杆子C 14 | tower(n, a, b, c) 15 | 16 | // 当 n=1 时,移动次数为 1 17 | // 当 n=2 时,移动次数为 3 18 | // 当 n=3 时,移动次数为 7 19 | // 当 n=4 时,移动次数为 15 20 | fmt.Println(total) 21 | } 22 | 23 | // 表示将N个盘子,从 a 杆,借助 b 杆移到 c 杆 24 | func tower(n int, a, b, c string) { 25 | if n == 1 { 26 | total = total + 1 27 | // fmt.Println(a, "->", c) 28 | return 29 | } 30 | 31 | tower(n-1, a, c, b) 32 | total = total + 1 33 | // fmt.Println(a, "->", c) 34 | tower(n-1, b, a, c) 35 | } 36 | -------------------------------------------------------------------------------- /algorithm/common/lfu_ache_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sirupsen/logrus" 7 | ) 8 | 9 | func TestLFUCache(t *testing.T) { 10 | lfuCache := NewLFUCache(3) 11 | lfuCache.Set(1, 11) 12 | lfuCache.Set(1, 11) 13 | lfuCache.Set(1, 11) 14 | lfuCache.Set(2, 22) 15 | lfuCache.Set(2, 22) 16 | lfuCache.Set(3, 33) 17 | lfuCache.Set(4, 44) // 会把3移除掉 18 | for _, v := range lfuCache.cacheMap { 19 | logrus.Printf("key:%v value:%v", v.key, v.value) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /algorithm/common/lru_cache_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sirupsen/logrus" 7 | ) 8 | 9 | func TestLRUCache(t *testing.T) { 10 | LRUCache := NewLRUCache(3) 11 | LRUCache.Set(1, 11) 12 | LRUCache.Set(2, 22) 13 | LRUCache.Set(3, 33) 14 | LRUCache.Set(4, 44) // 会把1移除掉 15 | LRUCache.Set(5, 55) // 会把1移除掉 16 | LRUCache.Set(6, 66) // 会把1移除掉 17 | for _, v := range LRUCache.m { 18 | logrus.Printf("key:%v value:%v", v.key, v.value) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /algorithm/common/stack_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestNewStack(t *testing.T) { 9 | s := NewStack(10) 10 | 11 | // for i := int64(0); i < 11; i++ { // stack is full 12 | for i := int64(0); i < 10; i++ { 13 | err := s.Push(i) 14 | if err != nil { 15 | t.Fatal(err) 16 | } 17 | fmt.Println("push:", i) 18 | } 19 | 20 | // for i := 0; i < 11; i++ { // stack is empty 21 | for i := 0; i < 10; i++ { 22 | pop, err := s.Pop() 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | fmt.Println("pop:", pop) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /algorithm/geektime/array-linkedlist-skiplist/1-283_move-zeroes_test.go: -------------------------------------------------------------------------------- 1 | package array_linkedlist_skiplist 2 | 3 | import "testing" 4 | 5 | func Test_moveZeroesxx(t *testing.T) { 6 | type args struct { 7 | nums []int 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | }{ 13 | {name: "1", args: args{nums: []int{1, 0, 1, 0, 1, 1, 0, 1}}}, 14 | } 15 | for _, tt := range tests { 16 | t.Run(tt.name, func(t *testing.T) { 17 | moveZeroesxx(tt.args.nums) 18 | }) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /algorithm/geektime/array-linkedlist-skiplist/10-26-remove-duplicates-from-sorted-array.go: -------------------------------------------------------------------------------- 1 | package array_linkedlist_skiplist 2 | 3 | // https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array 4 | func removeDuplicates(nums []int) int { 5 | n := len(nums) 6 | if n < 2 { 7 | return n 8 | } 9 | 10 | l, r := 1, 1 11 | for r < n { 12 | // 遇到不重复的则移动到 l 指针处,相同的则不管 13 | if nums[r] != nums[r-1] { 14 | nums[l] = nums[r] 15 | l++ 16 | } 17 | r++ 18 | } 19 | return l 20 | } 21 | -------------------------------------------------------------------------------- /algorithm/geektime/array-linkedlist-skiplist/13-88-merge-sorted-array.go: -------------------------------------------------------------------------------- 1 | package array_linkedlist_skiplist 2 | 3 | // https://leetcode-cn.com/problems/merge-sorted-array 4 | // 从后往前写 不需要额外空间 5 | func merge(nums1 []int, m int, nums2 []int, n int) { 6 | var ( 7 | pm = m - 1 8 | pn = n - 1 9 | p = m + n - 1 10 | ) 11 | for pn >= 0 { 12 | if pm >= 0 && nums1[pm] > nums2[pn] { 13 | nums1[p] = nums1[pm] 14 | pm-- 15 | p-- 16 | } else { 17 | nums1[p] = nums2[pn] 18 | pn-- 19 | p-- 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /algorithm/geektime/array-linkedlist-skiplist/4.1-1_two-sum.go: -------------------------------------------------------------------------------- 1 | package array_linkedlist_skiplist 2 | 3 | // https://leetcode-cn.com/problems/two-sum 4 | // 将 数组的值 和 下标 交换后存到 map 中 map 的 key 为 值 value 为下标 5 | func twoSum(nums []int, target int) []int { 6 | var m = make(map[int]int) 7 | for i, v := range nums { 8 | // 找出与当前值相加等于 target 的目标值 9 | find := target - v 10 | // 由于是反着存的 所以 如果 m[find]如果存在 那么他的 value 就是 数组的 index 11 | if j, ok := m[find]; ok { 12 | return []int{j, i} 13 | } 14 | m[v] = i 15 | } 16 | return []int{} 17 | } 18 | -------------------------------------------------------------------------------- /algorithm/geektime/array-linkedlist-skiplist/5-206_reverse-linked-list.go: -------------------------------------------------------------------------------- 1 | package array_linkedlist_skiplist 2 | 3 | // Definition for singly-linked list. 4 | type ListNode struct { 5 | Val int 6 | Next *ListNode 7 | } 8 | 9 | // https://leetcode.com/problems/reverse-linked-list/ 10 | func reverseList(head *ListNode) *ListNode { 11 | var ( 12 | prev *ListNode = nil 13 | curr = head 14 | tmp *ListNode 15 | ) 16 | for curr != nil { 17 | // 保存下一个节点 备用 18 | tmp = curr.Next 19 | // 反转当前节点 20 | curr.Next = prev 21 | // 移动到下一个位置 22 | prev = curr 23 | curr = tmp 24 | } 25 | return prev 26 | } 27 | -------------------------------------------------------------------------------- /algorithm/geektime/array-linkedlist-skiplist/6_24_swap-nodes-in-pairs.go: -------------------------------------------------------------------------------- 1 | package array_linkedlist_skiplist 2 | 3 | // https://leetcode.com/problems/swap-nodes-in-pairs 4 | func swapPairs(head *ListNode) *ListNode { 5 | // 创建一个节点用于记录 head 节点(后续交换中 head 节点会变) 6 | var dummy = &ListNode{ 7 | Val: -1, 8 | Next: head, 9 | } 10 | prev := dummy 11 | for head != nil && head.Next != nil { 12 | // 找到需要交换的两个节点 13 | first := head 14 | second := head.Next 15 | // 开始交换 16 | prev.Next = second 17 | first.Next = second.Next 18 | second.Next = first 19 | // 循环到后续两个节点(当前 first 节点已经是第二个节点了) 20 | prev = first 21 | head = first.Next 22 | } 23 | // 这里直接返回 head 节点 24 | return dummy.Next 25 | } 26 | -------------------------------------------------------------------------------- /algorithm/geektime/array-linkedlist-skiplist/7-141_linked-list-cycle.go: -------------------------------------------------------------------------------- 1 | package array_linkedlist_skiplist 2 | 3 | // https://leetcode-cn.com/problems/linked-list-cycle/submissions/ 4 | func hasCycle(head *ListNode) bool { 5 | if head == nil { 6 | return false 7 | } 8 | var ( 9 | slow = head 10 | fast = head.Next 11 | ) 12 | 13 | for fast != nil && fast.Next != nil && fast.Next.Next != nil { 14 | if slow == fast { 15 | return true 16 | } 17 | slow = slow.Next 18 | fast = fast.Next.Next 19 | } 20 | return false 21 | } 22 | -------------------------------------------------------------------------------- /algorithm/geektime/array-linkedlist-skiplist/8-142_linked-list-cycle-ii.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lixd/i-go/d2d1491693f31efa867c5132765bbe4e693f25dc/algorithm/geektime/array-linkedlist-skiplist/8-142_linked-list-cycle-ii.png -------------------------------------------------------------------------------- /algorithm/geektime/bfsdfs/1-102-binary-tree-level-order-traversal_test.go: -------------------------------------------------------------------------------- 1 | package bfsdfs 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func Test_dfs(t *testing.T) { 9 | r := &TreeNode{ 10 | Val: 1, 11 | Left: &TreeNode{ 12 | Val: 1, 13 | Left: &TreeNode{ 14 | Val: 3, 15 | Left: nil, 16 | Right: nil, 17 | }, 18 | Right: nil, 19 | }, 20 | Right: &TreeNode{ 21 | Val: 2, 22 | Left: &TreeNode{ 23 | Val: 4, 24 | Left: nil, 25 | Right: nil, 26 | }, 27 | Right: nil, 28 | }, 29 | } 30 | res := make([][]int, 0) 31 | res = dfs(r, 0, res) 32 | fmt.Println(res) 33 | } 34 | -------------------------------------------------------------------------------- /algorithm/geektime/bfsdfs/3-22-generate-parentheses.go: -------------------------------------------------------------------------------- 1 | package bfsdfs 2 | 3 | func generateParenthesis(n int) []string { 4 | var res []string 5 | return res 6 | } 7 | -------------------------------------------------------------------------------- /algorithm/geektime/bfsdfs/8-126-word-ladder-ii.go: -------------------------------------------------------------------------------- 1 | package bfsdfs 2 | 3 | // https://leetcode-cn.com/problems/word-ladder-ii 4 | func findLadders(beginWord string, endWord string, wordList []string) [][]string { 5 | return nil 6 | } 7 | -------------------------------------------------------------------------------- /algorithm/geektime/bfsdfs/bfs_template.go: -------------------------------------------------------------------------------- 1 | package bfsdfs 2 | 3 | // 广度优先 每次遍历时记录当前层的结果并将下一层节点存储起来等待下一次遍历 4 | /* 5 | visited = set() 6 | def bfs(graph,start,end): 7 | 8 | queue = [] 9 | queue.append([start]) 10 | visited.add(start) 11 | 12 | while queue: 13 | node=queue.pop() 14 | visited.add(node) 15 | process(node) 16 | // 每次存储当前节点相关联的下一层级节点 17 | nodes = generate_related_nodes(node) 18 | queue.push(nodes) 19 | // other process working 20 | */ 21 | -------------------------------------------------------------------------------- /algorithm/geektime/bfsdfs/dfs_template.go: -------------------------------------------------------------------------------- 1 | package bfsdfs 2 | 3 | // 深度优先 每次遍历直接进入下一层循环,如果有的话,直到某个分支循环到底了再返回到最开始的循环 4 | /* 5 | visited =set() 6 | 7 | def dfs(node,visited): 8 | // 如果访问过 直接返回 9 | if node in visited { 10 | return 11 | } 12 | // 否则添加到已访问列表 13 | visited.add(node) 14 | // process current node here. 15 | for next_node in node.children() 16 | // // 不等当前层循环走完 直接进入下一层循环 17 | if not next_ndoe in visited: 18 | dfs(next_node,visited) 19 | */ 20 | -------------------------------------------------------------------------------- /algorithm/geektime/bfsdfs/node.go: -------------------------------------------------------------------------------- 1 | package bfsdfs 2 | 3 | // TreeNode Definition for a binary tree node. 4 | type TreeNode struct { 5 | Val int 6 | Left *TreeNode 7 | Right *TreeNode 8 | } 9 | -------------------------------------------------------------------------------- /algorithm/geektime/binary-search/1-69-sqrtx_test.go: -------------------------------------------------------------------------------- 1 | package binary_search 2 | 3 | import "testing" 4 | 5 | func Test_mySqrt(t *testing.T) { 6 | type args struct { 7 | x int 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want int 13 | }{ 14 | {name: "1", args: args{1}, want: 1}, 15 | {name: "2", args: args{2}, want: 1}, 16 | {name: "4", args: args{4}, want: 2}, 17 | } 18 | for _, tt := range tests { 19 | t.Run(tt.name, func(t *testing.T) { 20 | if got := mySqrt(tt.args.x); got != tt.want { 21 | t.Errorf("mySqrt() = %v, want %v", got, tt.want) 22 | } 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /algorithm/geektime/binary-search/2-367-valid-perfect-square.go: -------------------------------------------------------------------------------- 1 | package binary_search 2 | 3 | // https://leetcode-cn.com/problems/valid-perfect-square 4 | func isPerfectSquare(num int) bool { 5 | var ( 6 | l, r = 0, num 7 | ) 8 | for l <= r { 9 | mid := l + (r-l)/2 10 | if mid*mid == num { 11 | return true 12 | } else if mid*mid < num { 13 | l = mid + 1 14 | } else { 15 | r = mid - 1 16 | } 17 | } 18 | return false 19 | } 20 | -------------------------------------------------------------------------------- /algorithm/geektime/binary-search/template.go: -------------------------------------------------------------------------------- 1 | package binary_search 2 | 3 | // binarySearch 二分查找模板代码(假设array是升序排列的) 4 | func binarySearch(array []int, target int) int { 5 | var ( 6 | // 1.首先确定左右边界 7 | left, right = 0, len(array) - 1 8 | ) 9 | // 一直循环到左下边界大于右边界 还没找到则说明没有这个值 10 | for left <= right { 11 | // 取中间值 12 | mid := (left + right) / 2 13 | // 相等则直接返回 14 | if array[mid] == target { 15 | return mid 16 | } else if array[mid] < target { 17 | // 小于则说明目标值在右边 将左边界向右移 18 | left = right + 1 19 | } else { 20 | // 否则说明目标值在左边 将右边界向左移 21 | right = mid - 1 22 | } 23 | } 24 | return -1 25 | } 26 | -------------------------------------------------------------------------------- /algorithm/geektime/divide-conquer-backtracking/1-50-powx-n.go: -------------------------------------------------------------------------------- 1 | package recursion 2 | 3 | // https://leetcode-cn.com/problems/powx-n/ 4 | // 1.暴力解法 for 循环 把x乘N次 5 | // 2.分治 1.terminator 2.process(spilt problem) 3.drill down(subproblem),merge result 4.reverse states 6 | // pow(x,n)-->pow(x,n/2) n需要区分正负和奇偶 7 | // 3.牛顿迭代法 8 | func myPow(x float64, n int) float64 { 9 | if n < 0 { 10 | // 负数和正数区分 11 | return 1.0 / pow(x, -n) 12 | } 13 | return pow(x, n) 14 | } 15 | func pow(x float64, n int) float64 { 16 | if n == 0 { 17 | return 1 18 | } 19 | sub := pow(x, n/2) 20 | // odd even 区分 21 | if n%2 == 0 { 22 | return sub * sub 23 | } 24 | // odd 除2之后会漏掉一个 所以最后补上 25 | return sub * sub * x 26 | } 27 | -------------------------------------------------------------------------------- /algorithm/geektime/divide-conquer-backtracking/3-169-majority-element.go: -------------------------------------------------------------------------------- 1 | package recursion 2 | 3 | // https://leetcode-cn.com/problems/majority-element/ 4 | // 题解 https://leetcode-cn.com/problems/majority-element/ 5 | // 众数是出现次数大于二分之一的数 因此按照抵消法抵消后 最后剩余的一定是众数 6 | /* 7 | 1.利用map统计元素出现的次数 8 | 2.利用大于 ⌊ n/2 ⌋ 的特性 该方法就是用到了这个特性 摩尔投票算法 9 | 3.先排序,在查找 10 | 4.暴力破解,双重for循环就不写了 11 | */ 12 | func majorityElement(nums []int) int { 13 | var ( 14 | major = 0 15 | count = 0 16 | ) 17 | for _, v := range nums { 18 | if count == 0 { 19 | major = v 20 | } 21 | if major == v { 22 | count++ 23 | } else { 24 | count-- 25 | } 26 | 27 | } 28 | return major 29 | } 30 | -------------------------------------------------------------------------------- /algorithm/geektime/greedy/2-455-assign-cookies.go: -------------------------------------------------------------------------------- 1 | package greedy 2 | 3 | import "sort" 4 | 5 | // https://leetcode-cn.com/problems/assign-cookies/description/ 6 | func findContentChildren(g []int, s []int) int { 7 | // 排好序后一次遍历即可 8 | // 贪心算法 每个孩子都找刚好能满足其胃口的饼干从而使得饼干作用最大化 9 | sort.Ints(g) 10 | sort.Ints(s) 11 | var i, j int 12 | for i < len(g) && j < len(s) { 13 | // 如果找到满足条件的饼干则直接i++去匹配下一个孩子 14 | if g[i] <= s[j] { 15 | i++ 16 | } 17 | // 不管满不满足都要j++,因为 g s都是有序的,当前不满足则只能往后找更大的饼干,满足则当前饼干被用掉了 也不能再用了 18 | j++ 19 | } 20 | return i 21 | } 22 | -------------------------------------------------------------------------------- /algorithm/geektime/greedy/3-860-lemonade-change.go: -------------------------------------------------------------------------------- 1 | package greedy 2 | 3 | // https://leetcode-cn.com/problems/lemonade-change/description/ 4 | func lemonadeChange(bills []int) bool { 5 | var five, ten int 6 | for _, bill := range bills { 7 | switch bill { 8 | case 5: 9 | five++ 10 | case 10: 11 | if five < 1 { 12 | return false 13 | } 14 | ten++ 15 | five-- 16 | case 20: 17 | if five > 0 && ten > 0 { 18 | five-- 19 | ten-- 20 | } else if five > 3 { 21 | five -= 3 22 | } else { 23 | return false 24 | } 25 | } 26 | } 27 | return true 28 | } 29 | -------------------------------------------------------------------------------- /algorithm/geektime/greedy/4-122-best-time-to-buy-and-sell-stock-ii.go: -------------------------------------------------------------------------------- 1 | package greedy 2 | 3 | // https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ 4 | func maxProfit(prices []int) int { 5 | var maxProfit int 6 | for i := 1; i < len(prices); i++ { 7 | if prices[i] > prices[i-1] { 8 | // 所有的收益点累加起来 最后收益一定是最大的 9 | maxProfit += prices[i] - prices[i-1] 10 | } 11 | } 12 | return maxProfit 13 | } 14 | -------------------------------------------------------------------------------- /algorithm/geektime/greedy/template.go: -------------------------------------------------------------------------------- 1 | package greedy 2 | 3 | // 贪心算法 4 | /* 5 | 贪心算法:当下做局部最优,从而达到全局最优(实际情况是每一步都最优可能结果也不是最优) 6 | 回溯:能够回退 7 | 动态规划:最优判断+回退(保存当前的结果并在适当的时候进行回退)(带最优判断的回溯就叫动态规划) 8 | 9 | 贪心算法可以解决一些最优化问题,如:求图中的最小生成树、求哈夫曼编码等。然而对于工程和生活中的一些问题,贪心法一般不能得到我们所要求的答案。 10 | 11 | 一旦某个问题可以通过贪心算法来解决,那么贪心算法一般就是解决该问题的最好办法。 12 | 由于贪心法的高效性以及其所得答案比较接近最优结果,贪心法也可以用作辅助算法或者直接解决一些要求结果不特别精确的问题。 13 | */ 14 | -------------------------------------------------------------------------------- /algorithm/geektime/hash-map-set/1-242-valid-anagram_test.go: -------------------------------------------------------------------------------- 1 | package hash_map_set 2 | 3 | import "testing" 4 | 5 | func Test_isAnagram(t *testing.T) { 6 | s1 := "axx" 7 | s2 := "xxa" 8 | isAnagram(s1, s2) 9 | } 10 | -------------------------------------------------------------------------------- /algorithm/geektime/hash-map-set/3-1-two-sum.go: -------------------------------------------------------------------------------- 1 | package hash_map_set 2 | 3 | // https://leetcode-cn.com/problems/two-sum/description/ 4 | func twoSum(nums []int, target int) []int { 5 | var m = make(map[int]int) 6 | for i, v := range nums { 7 | find := target - v 8 | if k, ok := m[find]; ok { 9 | return []int{k, i} 10 | } 11 | m[v] = i 12 | } 13 | return nil 14 | } 15 | -------------------------------------------------------------------------------- /algorithm/geektime/recursion/1-70-climbing-stairs.go: -------------------------------------------------------------------------------- 1 | package recursion 2 | 3 | // https://leetcode-cn.com/problems/climbing-stairs/ 4 | func climbStairs(n int) int { 5 | if n <= 3 { 6 | return n 7 | } 8 | return climbStairs(n-1) + climbStairs(n-2) 9 | } 10 | func climbStairs2(n int) int { 11 | if n <= 3 { 12 | return n 13 | } 14 | f1, f2, f3 := 1, 2, 3 15 | // 不需要完整的 Fibonacci 数列,所以只需要保存中间 3 个变量即可 16 | for i := 3; i < n+1; i++ { 17 | f3 = f1 + f2 18 | f1 = f2 19 | f2 = f3 20 | } 21 | return f3 22 | } 23 | -------------------------------------------------------------------------------- /algorithm/geektime/recursion/1-70-climbing-stairs_test.go: -------------------------------------------------------------------------------- 1 | package recursion 2 | 3 | import "testing" 4 | 5 | func Test_climbStairs(t *testing.T) { 6 | type args struct { 7 | n int 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want int 13 | }{ 14 | {name: "1", args: args{n: 1}, want: 1}, 15 | {name: "2", args: args{n: 2}, want: 2}, 16 | {name: "4", args: args{n: 4}, want: 5}, 17 | } 18 | for _, tt := range tests { 19 | t.Run(tt.name, func(t *testing.T) { 20 | if got := climbStairs2(tt.args.n); got != tt.want { 21 | t.Errorf("climbStairs() = %v, want %v", got, tt.want) 22 | } 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /algorithm/geektime/recursion/10-77-combinations.go: -------------------------------------------------------------------------------- 1 | package recursion 2 | 3 | // 回溯 https://leetcode-cn.com/problems/combinations/solution/hui-su-si-xiang-tuan-mie-pai-lie-zu-he-zi-ji-wen-2/ 4 | func combine(n int, k int) [][]int { 5 | var res [][]int 6 | return res 7 | } 8 | func combiner(left, right, k int, res *[][]int) { 9 | // terminator 10 | if left > right { 11 | return 12 | } 13 | // process 14 | for i := 0; i < k; i++ { 15 | 16 | } 17 | // drill down 18 | // restore status 19 | } 20 | -------------------------------------------------------------------------------- /algorithm/geektime/recursion/2-22-generate-parentheses.go: -------------------------------------------------------------------------------- 1 | package recursion 2 | 3 | // https://leetcode-cn.com/problems/generate-parentheses/ 4 | func generateParenthesis(n int) []string { 5 | var res []string 6 | generate(0, 0, n, "", &res) 7 | return res 8 | } 9 | func generate(left, right, n int, s string, res *[]string) { 10 | // terminator 11 | if left == n && right == n { 12 | *res = append(*res, s) 13 | return 14 | } 15 | // process current logic 16 | // drill down 17 | if left < n { 18 | generate(left+1, right, n, s+"(", res) 19 | } 20 | if left > right { 21 | generate(left, right+1, n, s+")", res) 22 | } 23 | // restore current status 24 | } 25 | -------------------------------------------------------------------------------- /algorithm/geektime/recursion/3-226-invert-binary-tree.go: -------------------------------------------------------------------------------- 1 | package recursion 2 | 3 | // https://leetcode-cn.com/problems/invert-binary-tree/submissions/ 4 | func invertTree(root *TreeNode) *TreeNode { 5 | invert(root) 6 | return root 7 | } 8 | 9 | func invert(root *TreeNode) { 10 | // terminator 11 | if root == nil { 12 | return 13 | } 14 | // process current logic 15 | root.Right, root.Left = root.Left, root.Right 16 | // drill down 17 | if root.Left != nil { 18 | invert(root.Left) 19 | } 20 | if root.Right != nil { 21 | invert(root.Right) 22 | } 23 | // restore current status 24 | } 25 | -------------------------------------------------------------------------------- /algorithm/geektime/recursion/model.go: -------------------------------------------------------------------------------- 1 | package recursion 2 | 3 | // Definition for a binary tree node. 4 | type TreeNode struct { 5 | Val int 6 | Left *TreeNode 7 | Right *TreeNode 8 | } 9 | -------------------------------------------------------------------------------- /algorithm/geektime/recursion/template.go: -------------------------------------------------------------------------------- 1 | package recursion 2 | 3 | // recursion 递归 模板代码 4 | func recursion(level, params int) { 5 | // 1.首先写递归终结条件 terminator 6 | if level > 999 { 7 | // process result 8 | return 9 | } 10 | // 2.处理当前层逻辑 process current logic 11 | process(level, params) 12 | // 3.下探到下一层 drill down 13 | recursion(level+1, params) 14 | // 4.清理当前层 restore current status 15 | } 16 | 17 | func process(level, params int) { 18 | 19 | } 20 | -------------------------------------------------------------------------------- /algorithm/geektime/stack-queue-deque/2-155-min-stack_test.go: -------------------------------------------------------------------------------- 1 | package stack_queue_deque 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestMinStack_Pop(t *testing.T) { 9 | obj := Constructor() 10 | obj.Push(1) 11 | obj.Pop() 12 | param_3 := obj.Top() 13 | fmt.Println(param_3) 14 | param_4 := obj.GetMin() 15 | fmt.Println(param_4) 16 | } 17 | -------------------------------------------------------------------------------- /algorithm/geektime/stack-queue-deque/3-84-largest-rectangle-in-histogram_test.go: -------------------------------------------------------------------------------- 1 | package stack_queue_deque 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func Test_largestRectangleArea(t *testing.T) { 9 | array := []int{4, 2} 10 | fmt.Println(largestRectangleArea(array)) 11 | } 12 | -------------------------------------------------------------------------------- /algorithm/geektime/tree/1-94-binary-tree-inorder-traversal.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | // https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ 4 | func inorderTraversal(root *TreeNode) []int { 5 | var res []int 6 | inorder(root, &res) 7 | return res 8 | } 9 | 10 | func inorder(root *TreeNode, res *[]int) { 11 | if root == nil { 12 | return 13 | } 14 | inorder(root.Left, res) 15 | *res = append(*res, root.Val) 16 | inorder(root.Right, res) 17 | } 18 | -------------------------------------------------------------------------------- /algorithm/geektime/tree/2-144-binary-tree-preorder-traversal.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | // https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ 4 | func preorderTraversal(root *TreeNode) []int { 5 | var res []int 6 | preOrder(root, &res) 7 | return res 8 | } 9 | func preOrder(root *TreeNode, res *[]int) { 10 | if root == nil { 11 | return 12 | } 13 | *res = append(*res, root.Val) 14 | preOrder(root.Left, res) 15 | preOrder(root.Right, res) 16 | } 17 | -------------------------------------------------------------------------------- /algorithm/geektime/tree/3-509-n-ary-tree-postorder-traversal.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | // https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/ 4 | func postorder(root *Node) []int { 5 | var res []int 6 | postOrder(root, &res) 7 | return res 8 | } 9 | func postOrder(root *Node, res *[]int) { 10 | if root == nil { 11 | return 12 | } 13 | for _, v := range root.Children { 14 | postOrder(v, res) 15 | } 16 | *res = append(*res, root.Val) 17 | } 18 | -------------------------------------------------------------------------------- /algorithm/geektime/tree/4-589-n-ary-tree-preorder-traversal.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | // https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/ 4 | func preorder(root *Node) []int { 5 | var res []int 6 | nAryPreOrder(root, &res) 7 | return res 8 | } 9 | func nAryPreOrder(root *Node, res *[]int) { 10 | if root == nil { 11 | return 12 | } 13 | *res = append(*res, root.Val) 14 | for _, v := range root.Children { 15 | nAryPreOrder(v, res) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /algorithm/geektime/tree/5-429-n-ary-tree-level-order-traversal.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | // https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/ 4 | // 广度优先 5 | func levelOrder(root *Node) [][]int { 6 | var res [][]int 7 | levelOrders(root, &res, 0) 8 | return res 9 | } 10 | 11 | func levelOrders(root *Node, res *[][]int, level int) { 12 | if root == nil { 13 | return 14 | } 15 | if len(*res) == level { 16 | *res = append(*res, []int{}) 17 | } 18 | (*res)[level] = append((*res)[level], root.Val) 19 | for _, v := range root.Children { 20 | levelOrders(v, res, level+1) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /algorithm/geektime/tree/model.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | // Definition for a binary tree node. 4 | type TreeNode struct { 5 | Val int 6 | Left *TreeNode 7 | Right *TreeNode 8 | } 9 | 10 | // Definition for a Node. 11 | type Node struct { 12 | Val int 13 | Children []*Node 14 | } 15 | -------------------------------------------------------------------------------- /algorithm/leetcode/array/difficult/find_median_sorted_arrays.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | /* 6 | 寻找两个正序数组的中位数 困难 7 | 8 | 给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。 9 | 请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。 10 | 你可以假设 nums1 和 nums2 不会同时为空。 11 | 12 | nums1 = [1, 3] 13 | nums2 = [2] 14 | 则中位数是 2.0 15 | 16 | nums1 = [1, 2] 17 | nums2 = [3, 4] 18 | 则中位数是 (2 + 3)/2 = 2.5 19 | */ 20 | func main() { 21 | nums1 := []int{} 22 | nums2 := []int{} 23 | fmt.Println(findMedianSortedArrays(nums1, nums2)) 24 | } 25 | 26 | func findMedianSortedArrays(nums1 []int, nums2 []int) float64 { 27 | return 0 28 | } 29 | -------------------------------------------------------------------------------- /algorithm/leetcode/array/middle/495-teemo-attacking.go: -------------------------------------------------------------------------------- 1 | package middle 2 | 3 | // findPoisonedDuration 4 | // https://leetcode-cn.com/problems/teemo-attacking/ 5 | func findPoisonedDuration(timeSeries []int, duration int) int { 6 | var ( 7 | res int 8 | span int 9 | ) 10 | if len(timeSeries) <= 1 { 11 | return len(timeSeries) * duration 12 | } 13 | for i := 1; i < len(timeSeries); i++ { 14 | span = timeSeries[i] - timeSeries[i-1] 15 | if span > duration { 16 | res += duration 17 | } else { 18 | res += span 19 | } 20 | } 21 | // 最后一次攻击必定持续 duration 时间 22 | res += duration 23 | return res 24 | } 25 | -------------------------------------------------------------------------------- /algorithm/leetcode/array/middle/subsets.go: -------------------------------------------------------------------------------- 1 | package middle 2 | 3 | /* 4 | 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 中等 5 | 说明:解集不能包含重复的子集。 6 | 7 | 输入: nums = [1,2,3] 8 | 输出: 9 | [ 10 | [3], 11 |   [1], 12 |   [2], 13 |   [1,2,3], 14 |   [1,3], 15 |   [2,3], 16 |   [1,2], 17 |   [] 18 | ] 19 | 20 | */ 21 | func main() { 22 | 23 | } 24 | 25 | func subsets(nums []int) [][]int { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /algorithm/leetcode/array/simple/two_sum.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | /* 6 | 两数之和 7 | 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 8 | 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。 9 | 10 | 给定 nums = [2, 7, 11, 15], target = 9 11 | 12 | 因为 nums[0] + nums[1] = 2 + 7 = 9 13 | 所以返回 [0, 1] 14 | */ 15 | func main() { 16 | nums := []int{1, 3, 5, 7, 9} 17 | target := 4 18 | fmt.Println(twoSum(nums, target)) 19 | } 20 | 21 | func twoSum(nums []int, target int) []int { 22 | m := make(map[int]int) 23 | for i, v := range nums { 24 | if j, ok := m[target-v]; ok { 25 | return []int{j, i} 26 | } 27 | m[v] = i 28 | } 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/1018-binary-prefix-divisible-by-5.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/binary-prefix-divisible-by-5/ 4 | /* 5 | 判定能否被5整除 只需要看最后一位是不是0或者5 所以直接模10获取最后一位 这样还可以防止溢出 6 | 然后每次都要在末尾加一个数 所以直接左移然后模10最后加上当前数即可 7 | */ 8 | func prefixesDivBy5(A []int) []bool { 9 | ans := make([]bool, len(A)) 10 | // r 11 | r := 0 12 | for i, n := range A { 13 | // 01<<1 + 1 =011 14 | r = (r<<1)%10 + n 15 | ans[i] = r%5 == 0 16 | } 17 | 18 | return ans 19 | } 20 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/1128.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/number-of-equivalent-domino-pairs/ 4 | func numEquivDominoPairs(dominoes [][]int) int { 5 | var ( 6 | cnt = [100]int{} // 用哈希表来记录对应key出现的次数,由于只有100个值 所以优化成数组 7 | ans int 8 | ) 9 | for _, d := range dominoes { 10 | // 默认用小的值*10+大的值 作为数组的索引 11 | if d[0] > d[1] { 12 | // 如果d[0]为大值则和小值d[1]交换 13 | // 这样[1,2] [2,1] 最终交换后都是[1,2]这样的形式 14 | d[0], d[1] = d[1], d[0] 15 | } 16 | i := d[0]*10 + d[1] // 计算对应的索引 可以当做是一个简单的hash函数 17 | ans += cnt[i] 18 | cnt[i]++ 19 | } 20 | return ans 21 | } 22 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/1128_test.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | import "testing" 4 | 5 | func Test_numEquivDominoPairs(t *testing.T) { 6 | type args struct { 7 | dominoes [][]int 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want int 13 | }{ 14 | {name: "1", args: struct{ dominoes [][]int }{dominoes: [][]int{{1, 2}, {2, 1}, {3, 4}, {5, 6}}}, want: 1}, 15 | } 16 | for _, tt := range tests { 17 | t.Run(tt.name, func(t *testing.T) { 18 | if got := numEquivDominoPairs(tt.args.dominoes); got != tt.want { 19 | t.Errorf("numEquivDominoPairs() = %v, want %v", got, tt.want) 20 | } 21 | }) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/1202-smallest-string-with-swaps.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/smallest-string-with-swaps/ 4 | func smallestStringWithSwaps(s string, pairs [][]int) string { 5 | 6 | return "" 7 | } 8 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/189-rotate-array.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/rotate-array/ 4 | func rotate(nums []int, k int) { 5 | newNums := make([]int, len(nums)) 6 | for i, v := range nums { 7 | newNums[(i+k)%len(nums)] = v 8 | } 9 | copy(nums, newNums) 10 | } 11 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/205-isomorphic-strings.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/isomorphic-strings 4 | func isIsomorphic(s string, t string) bool { 5 | var ( 6 | s2t = make(map[byte]byte) 7 | t2s = make(map[byte]byte) 8 | ) 9 | for i := range s { 10 | x := s[i] 11 | y := t[i] 12 | // 分别检查两个map 其中一个有冲突则说明不是同构字符串 13 | if s2t[x] > 0 && s2t[x] != y || t2s[y] > 0 && t2s[y] != x { 14 | return false 15 | } 16 | //交叉存 方便后续遇到同样的字符串时好比较 17 | s2t[x] = y 18 | t2s[y] = x 19 | } 20 | return true 21 | } 22 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/205-isomorphic-strings_test.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | import "testing" 4 | 5 | func Test_isIsomorphic(t *testing.T) { 6 | type args struct { 7 | s string 8 | t string 9 | } 10 | tests := []struct { 11 | name string 12 | args args 13 | want bool 14 | }{ 15 | {name: "1", args: args{ 16 | s: "abbc", 17 | t: "deef", 18 | }, want: true}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | if got := isIsomorphic(tt.args.s, tt.args.t); got != tt.want { 23 | t.Errorf("isIsomorphic() = %v, want %v", got, tt.want) 24 | } 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/217-contains-duplicate.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | //https://leetcode-cn.com/problems/contains-duplicate/ 4 | func containsDuplicate(nums []int) bool { 5 | m := make(map[int]struct{}) 6 | for _, v := range nums { 7 | _, ok := m[v] 8 | if ok { 9 | return true 10 | } else { 11 | m[v] = struct{}{} 12 | } 13 | } 14 | return false 15 | } 16 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/330-patching-array.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/patching-array/ 4 | // 题解: https://leetcode-cn.com/problems/patching-array/solution/an-yao-qiu-bu-qi-shu-zu-tan-xin-suan-fa-b4bwr/ 5 | func minPatches(nums []int, n int) int { 6 | var ( 7 | total int // 累加后覆盖的范围 8 | count int // 需要补充的数字个数 9 | index int // 访问下标index 10 | ) 11 | 12 | for total < n { 13 | if index < len(nums) && nums[index] <= total+1 { 14 | // 如果当前数字在覆盖范围内就不用补充其他数 直接扩大覆盖范围然后继续下一个数 15 | total += nums[index] 16 | index++ 17 | } else { 18 | count++ // 每次都补充最大值 即 total+1 这样覆盖范围直接翻倍 19 | total = total + (total + 1) 20 | } 21 | } 22 | return count 23 | } 24 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/376-wiggle-subsequence.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/wiggle-subsequence/ 4 | 5 | func wiggleMaxLength(nums []int) int { 6 | n := len(nums) 7 | if n < 2 { 8 | return n 9 | } 10 | up, down := 1, 1 11 | for i := 1; i < n; i++ { 12 | // 当前元素小于前一个元素说明是下降序列否则为上升序列 相等则直接排除掉(不计入长度) 13 | if nums[i] > nums[i-1] { 14 | up = max(up, down+1) 15 | } else if nums[i] < nums[i-1] { 16 | down = max(up+1, down) 17 | } 18 | } 19 | return max(up, down) 20 | } 21 | 22 | func max(a, b int) int { 23 | if a > b { 24 | return a 25 | } 26 | return b 27 | } 28 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/387-first-unique-character-in-a-string.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/first-unique-character-in-a-string/ 4 | func firstUniqChar(s string) int { 5 | ch := make([]int, 26) 6 | for _, v := range s { 7 | ch[v-'a']++ 8 | } 9 | for i, v := range s { 10 | c := ch[v-'a'] 11 | if c == 1 { 12 | return i 13 | } 14 | } 15 | return -1 16 | } 17 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/389-find-the-difference.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/find-the-difference/ 4 | 5 | func findTheDifference(s string, t string) byte { 6 | m := make(map[int32]int) 7 | for _, v := range s { 8 | m[v]++ 9 | } 10 | for _, v := range t { 11 | m[v]-- 12 | if m[v] < 0 { 13 | return byte(v) 14 | } 15 | } 16 | return 0 17 | } 18 | func findTheDifference2(s string, t string) byte { 19 | var sum int 20 | for _, v := range t { 21 | sum += int(v) 22 | } 23 | for _, v := range s { 24 | sum -= int(v) 25 | } 26 | return byte(sum) 27 | } 28 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/399-evaluate-division.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/evaluate-division/ 4 | func calcEquation(equations [][]string, values []float64, queries [][]string) []float64 { 5 | 6 | return nil 7 | } 8 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/424.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | func characterReplacement(s string, k int) int { 4 | var ( 5 | maxCnt, left int 6 | cnt = [26]int{} 7 | ) 8 | for right, ch := range s { 9 | // 每次遍历时记录当前区间内该字符总出现次数 10 | cnt[ch-'A']++ 11 | // 找出最大值 然后 right-left+1 表示当前区间字符串 减去最大值就是剩下的不相等的字符串 12 | // 超过K则替换K个后也不能全部相等,所以需要移动left 进入下一个区间 13 | maxCnt = max(maxCnt, cnt[ch-'A']) 14 | if right-left+1-maxCnt > k { 15 | // 区间内不相等的字符大于k则当前区间无意义 16 | // left 往右移一位 然后把 cnt 中对应字符的计数减1 17 | cnt[s[left]-'A']-- 18 | left++ 19 | } 20 | } 21 | // 以上循环找到了满足条件的 left 的位置,left 右边的字符个数就是答案 22 | return len(s) - left 23 | } 24 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/424_test.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | import "testing" 4 | 5 | func Test_characterReplacement(t *testing.T) { 6 | type args struct { 7 | s string 8 | k int 9 | } 10 | tests := []struct { 11 | name string 12 | args args 13 | want int 14 | }{ 15 | {name: "1", args: args{"ABAB", 2}, want: 4}, 16 | {name: "2", args: args{"AAAABBC", 2}, want: 6}, 17 | {name: "3", args: args{"ABCCBA", 1}, want: 3}, 18 | } 19 | for _, tt := range tests { 20 | t.Run(tt.name, func(t *testing.T) { 21 | if got := characterReplacement(tt.args.s, tt.args.k); got != tt.want { 22 | t.Errorf("characterReplacement() = %v, want %v", got, tt.want) 23 | } 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/435-non-overlapping-intervals.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/non-overlapping-intervals/ 4 | func eraseOverlapIntervals(intervals [][]int) int { 5 | 6 | return 0 7 | } 8 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/455-assign-cookies.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | import "sort" 4 | 5 | // https://leetcode-cn.com/problems/assign-cookies/ 6 | func findContentChildren(g []int, s []int) int { 7 | sort.Ints(g) 8 | sort.Ints(s) 9 | var i, j int 10 | for i < len(s) && j < len(g) { 11 | if s[i] >= g[j] { 12 | j++ 13 | } 14 | i++ 15 | } 16 | return j 17 | } 18 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/455-assign-cookies_test.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | import "testing" 4 | 5 | func Test_findContentChildren(t *testing.T) { 6 | type args struct { 7 | g []int 8 | s []int 9 | } 10 | tests := []struct { 11 | name string 12 | args args 13 | want int 14 | }{ 15 | {name: "1", args: args{g: []int{1, 2, 3}, s: []int{1, 1}}, want: 1}, 16 | {name: "2", args: args{g: []int{1, 2}, s: []int{1, 2, 3}}, want: 2}, 17 | } 18 | for _, tt := range tests { 19 | t.Run(tt.name, func(t *testing.T) { 20 | if got := findContentChildren(tt.args.g, tt.args.s); got != tt.want { 21 | t.Errorf("findContentChildren() = %v, want %v", got, tt.want) 22 | } 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/49-group-anagrams.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | import "sort" 4 | 5 | // https://leetcode-cn.com/problems/group-anagrams/ 6 | func groupAnagrams(strs []string) [][]string { 7 | mp := map[string][]string{} 8 | // 互为字母异位词的字符串是相同的,只是顺序不一致,所以先进行排序 排序后肯定相同 9 | // 把排序后的值作为 key 即可 10 | for _, str := range strs { 11 | s := []byte(str) 12 | sort.Slice(s, func(i, j int) bool { 13 | return s[i] < s[j] 14 | }) 15 | sortedStr := string(s) 16 | mp[sortedStr] = append(mp[sortedStr], str) 17 | } 18 | ret := make([][]string, 0, len(mp)) 19 | for _, v := range mp { 20 | ret = append(ret, v) 21 | } 22 | return ret 23 | } 24 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/509-fibonacci-number.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/fibonacci-number/ 4 | func fib(n int) int { 5 | if n < 0 { 6 | return 0 7 | } 8 | if n < 2 { 9 | return n 10 | } 11 | // f=n1+n2 类似滑动窗口 不断更新这三个数就行了 12 | f, n1, n2 := 1, 0, 0 13 | for i := 2; i <= n; i++ { 14 | n2 = n1 15 | n1 = f 16 | f = n1 + n2 17 | } 18 | return f 19 | } 20 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/509-fibonacci-number_test.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test_fib(t *testing.T) { 8 | type args struct { 9 | n int 10 | } 11 | tests := []struct { 12 | name string 13 | args args 14 | want int 15 | }{ 16 | {name: "1", args: args{n: 3}, want: 2}, 17 | {name: "1", args: args{n: 4}, want: 3}, 18 | } 19 | for _, tt := range tests { 20 | t.Run(tt.name, func(t *testing.T) { 21 | if got := fib(tt.args.n); got != tt.want { 22 | t.Errorf("fib() = %v, want %v", got, tt.want) 23 | } 24 | }) 25 | } 26 | } 27 | 28 | func BenchmarkFib(b *testing.B) { 29 | for i := 0; i < b.N; i++ { 30 | fib(20) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/628-maximum-product-of-three-numbers.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | import ( 4 | "sort" 5 | ) 6 | 7 | // https://leetcode-cn.com/problems/maximum-product-of-three-numbers/ 8 | func maximumProduct(nums []int) int { 9 | sort.Ints(nums) 10 | n := len(nums) 11 | return max(nums[0]*nums[1]*nums[n-1], nums[n-3]*nums[n-2]*nums[n-1]) 12 | } 13 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/628-maximum-product-of-three-numbers_test.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | import "testing" 4 | 5 | func Test_maximumProduct(t *testing.T) { 6 | type args struct { 7 | nums []int 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want int 13 | }{ 14 | {name: "1", args: struct{ nums []int }{nums: []int{1, 2, 3}}, want: 6}, 15 | } 16 | for _, tt := range tests { 17 | t.Run(tt.name, func(t *testing.T) { 18 | if got := maximumProduct(tt.args.nums); got != tt.want { 19 | t.Errorf("maximumProduct() = %v, want %v", got, tt.want) 20 | } 21 | }) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/738-monotone-increasing-digits.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | import "strconv" 4 | 5 | // https://leetcode-cn.com/problems/monotone-increasing-digits/ 6 | func monotoneIncreasingDigits(n int) int { 7 | s := []byte(strconv.Itoa(n)) 8 | i := 1 9 | // 从低位往高位 找到第一个不满足单调递增的位置 i 10 | for i < len(s) && s[i] >= s[i-1] { 11 | i++ 12 | } 13 | if i < len(s) { 14 | // 从 i 开始往前把不是单调递增的前一位减少1 一直到满足单调递增 15 | for i > 0 && s[i] < s[i-1] { 16 | s[i-1]-- 17 | i-- 18 | } 19 | // 然后把后续全替换为9(因为前一位-1了) 20 | for i++; i < len(s); i++ { 21 | s[i] = '9' 22 | } 23 | } 24 | ans, _ := strconv.Atoi(string(s)) 25 | return ans 26 | } 27 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/738-monotone-increasing-digits_test.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func Test_monotoneIncreasingDigits(t *testing.T) { 9 | digits := monotoneIncreasingDigits(1243) 10 | fmt.Println(digits) 11 | } 12 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/746-min-cost-climbing-stairs_test.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | import "testing" 4 | 5 | func Test_minCostClimbingStairs(t *testing.T) { 6 | type args struct { 7 | cost []int 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want int 13 | }{ 14 | {name: "1", args: args{cost: []int{1, 100, 1, 1, 1, 100, 1, 1, 100, 1}}, want: 6}, 15 | } 16 | for _, tt := range tests { 17 | t.Run(tt.name, func(t *testing.T) { 18 | if got := minCostClimbingStairs(tt.args.cost); got != tt.want { 19 | t.Errorf("minCostClimbingStairs() = %v, want %v", got, tt.want) 20 | } 21 | }) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /algorithm/leetcode/daily/860-lemonade-change.go: -------------------------------------------------------------------------------- 1 | package daily 2 | 3 | // https://leetcode-cn.com/problems/lemonade-change/ 4 | func lemonadeChange(bills []int) bool { 5 | var ( 6 | five, ten int 7 | ) 8 | for _, v := range bills { 9 | switch v { 10 | case 5: 11 | five++ 12 | case 10: 13 | if five < 1 { 14 | return false 15 | } 16 | ten++ 17 | five-- 18 | case 20: 19 | // 3个5或者1个5 1个10 才能找零 20 | if ten > 0 && five > 0 { 21 | ten-- 22 | five-- 23 | } else if five > 3 { 24 | five -= 3 25 | } else { 26 | return false 27 | } 28 | } 29 | } 30 | return true 31 | } 32 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/03_test.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | import "testing" 4 | 5 | func Test_findRepeatNumber(t *testing.T) { 6 | type args struct { 7 | nums []int 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want int 13 | }{ 14 | {name: "1", args: args{[]int{2, 3, 1, 0, 2, 5, 3}}, want: 2}, 15 | {name: "2", args: args{[]int{1, 3, 1, 0, 2, 5, 3}}, want: 1}, 16 | } 17 | for _, tt := range tests { 18 | t.Run(tt.name, func(t *testing.T) { 19 | if got := findRepeatNumber2(tt.args.nums); got != tt.want { 20 | t.Errorf("findRepeatNumber() = %v, want %v", got, tt.want) 21 | } 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/04.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | // 由于二维数组是有规律的,所以可以利用这个规律在降低时间复杂度。 4 | // 从左下角开始寻找target,类似二分查找。 5 | func findNumberIn2DArray(matrix [][]int, target int) bool { 6 | var ( 7 | r = len(matrix) - 1 // 行 8 | c = 0 // 列 9 | ) 10 | if len(matrix) <= 0 || len(matrix[0]) <= 0 { 11 | return false 12 | } 13 | 14 | for r >= 0 && c < len(matrix[0]) { 15 | if matrix[r][c] == target { 16 | return true 17 | } 18 | if matrix[r][c] > target { 19 | r-- 20 | } else if matrix[r][c] < target { 21 | c++ 22 | } 23 | } 24 | return false 25 | } 26 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/04_test.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | import "testing" 4 | 5 | func Test_findNumberIn2DArray(t *testing.T) { 6 | type args struct { 7 | matrix [][]int 8 | target int 9 | } 10 | tests := []struct { 11 | name string 12 | args args 13 | want bool 14 | }{ 15 | {name: "1", args: args{ 16 | matrix: [][]int{{-5}}, 17 | target: -5, 18 | }, want: true}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | if got := findNumberIn2DArray(tt.args.matrix, tt.args.target); got != tt.want { 23 | t.Errorf("findNumberIn2DArray() = %v, want %v", got, tt.want) 24 | } 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/06.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | // https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/ 4 | // 全部存到数组中去,然后反转数组 这样会比递归快一些 5 | func reversePrint(head *ListNode) []int { 6 | var ans = make([]int, 0) 7 | for head != nil { 8 | ans = append(ans, head.Val) 9 | head = head.Next 10 | } 11 | reverse(ans) 12 | return ans 13 | } 14 | 15 | func reverse(arr []int) { 16 | for i := 0; i < len(arr)/2; i++ { 17 | arr[i], arr[len(arr)-i-1] = arr[len(arr)-i-1], arr[i] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/10-1.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | func fib(n int) int { 4 | var mod = 1000000007 5 | if n < 2 { 6 | return n 7 | } 8 | return (fib(n-1) + fib(n-2)) % mod 9 | } 10 | 11 | func fib2(n int) int { 12 | var mod = 1000000007 13 | if n < 2 { 14 | return n 15 | } 16 | var f, n1, n2 = 1, 0, 0 17 | for i := 2; i <= n; i++ { 18 | n2 = n1 19 | n1 = f 20 | f = (n1 + n2) % mod // 题目要求 21 | } 22 | return f 23 | } 24 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/10-2.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | // https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof/ 4 | /* 5 | 类似 斐波那契数列 6 | 区别是前面几阶: 7 | f(0)=1 默认开始就在第0阶,所以也算是一种 8 | f(1)=1 第一阶肯定只有一种 9 | f(2)=2 可以从0阶一次走两阶上来,也可以从1阶一次走1阶走上来 10 | 第n阶台阶可以从第n-1阶一次走一阶走上去,也可以从n-2阶一次走两阶走上去 11 | 所以:fn=f(n-1)+f(n-2) 12 | */ 13 | func numWays(n int) int { 14 | var mod = 1000000007 15 | if n <= 1 { 16 | return 1 17 | } 18 | if n == 2 { 19 | return 2 20 | } 21 | var f, n1, n2 = 2, 1, 1 22 | for i := 3; i <= n; i++ { 23 | n2 = n1 24 | n1 = f 25 | f = (n1 + n2) % mod 26 | } 27 | return f 28 | } 29 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/10-2_test.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | import "testing" 4 | 5 | func Test_numWays(t *testing.T) { 6 | type args struct { 7 | n int 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want int 13 | }{ 14 | {name: "1", args: args{n: 1}, want: 1}, 15 | {name: "2", args: args{n: 2}, want: 2}, 16 | {name: "7", args: args{n: 7}, want: 21}, 17 | } 18 | for _, tt := range tests { 19 | t.Run(tt.name, func(t *testing.T) { 20 | if got := numWays(tt.args.n); got != tt.want { 21 | t.Errorf("numWays() = %v, want %v", got, tt.want) 22 | } 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/14-2.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | /* 4 | 2 <= n <= 1000 n取值比较大,所以不能用dp了,可能会越界。 5 | 6 | 当绳子长度大于4时,尽可能多的分成长度为3的小段,这样乘积是最大的。(数学证明自行查找) 7 | 所以只需要把n大于4时切分出3就行了 8 | */ 9 | func cuttingRope2(n int) int { 10 | // 2 <= n <= 1000 11 | if n <= 3 { 12 | return n - 1 13 | } 14 | var ( 15 | sum int64 = 1 16 | mod = int64(1000000007) 17 | ) 18 | // 只要n大于4就切分一个3出来 等于4就别切了 19 | // 因为4最大切分为2*2还是等于4 切分为1*3反而变小了 20 | for n > 4 { 21 | sum *= 3 22 | sum %= mod 23 | n -= 3 24 | } 25 | sum *= int64(n) 26 | sum %= mod 27 | return int(sum) 28 | } 29 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/14-2_test.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test_cuttingRope2(t *testing.T) { 8 | type args struct { 9 | n int 10 | } 11 | tests := []struct { 12 | name string 13 | args args 14 | want int 15 | }{ 16 | {name: "2", args: args{n: 2}, want: 1}, 17 | {name: "3", args: args{n: 10}, want: 36}, 18 | } 19 | for _, tt := range tests { 20 | t.Run(tt.name, func(t *testing.T) { 21 | if got := cuttingRope2(tt.args.n); got != tt.want { 22 | t.Errorf("cuttingRope2() = %v, want %v", got, tt.want) 23 | } 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/14_test.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | import "testing" 4 | 5 | func Test_cuttingRope(t *testing.T) { 6 | type args struct { 7 | n int 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want int 13 | }{ 14 | {name: "2", args: args{n: 2}, want: 1}, 15 | {name: "3", args: args{n: 10}, want: 36}, 16 | } 17 | for _, tt := range tests { 18 | t.Run(tt.name, func(t *testing.T) { 19 | if got := cuttingRope(tt.args.n); got != tt.want { 20 | t.Errorf("cuttingRope() = %v, want %v", got, tt.want) 21 | } 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/15.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | // https://leetcode-cn.com/problems/er-jin-zhi-zhong-1de-ge-shu-lcof/ 4 | func hammingWeight(num uint32) int { 5 | var sum int 6 | for num != 0 { 7 | // 只有1&1=1 8 | // 1的位数和num不一致,默认会在前面补0,所以这些补出来的位数&只会结果都为0 最终影响结果的就只有num的最后一位 9 | // 111x & 1 --> 111x & 0001 --> x & 1 10 | sum += int(num & 1) 11 | num >>= 1 12 | } 13 | return sum 14 | } 15 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/15_test.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test_hammingWeight(t *testing.T) { 8 | type args struct { 9 | num uint32 10 | } 11 | tests := []struct { 12 | name string 13 | args args 14 | want int 15 | }{ 16 | {name: "1", args: args{num: 9}, want: 2}, 17 | } 18 | for _, tt := range tests { 19 | t.Run(tt.name, func(t *testing.T) { 20 | if got := hammingWeight(tt.args.num); got != tt.want { 21 | t.Errorf("hammingWeight() = %v, want %v", got, tt.want) 22 | } 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/18.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | // https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof/ 4 | func deleteNode(head *ListNode, val int) *ListNode { 5 | if head == nil { 6 | return head 7 | } 8 | if head.Val == val { 9 | return head.Next 10 | } 11 | 12 | h := head // 单独把head记录下来,方便后续直接返回 13 | for h.Next != nil { 14 | // 找到待删除节点则删除并退出循环 15 | if h.Next.Val == val { 16 | h.Next = h.Next.Next 17 | break 18 | } 19 | // 否则遍历到下一个节点 20 | h = h.Next 21 | } 22 | return head 23 | } 24 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/21.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | // https://leetcode-cn.com/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof/ 4 | func exchange(nums []int) []int { 5 | // 双指针,前后遍历 6 | left, right := 0, len(nums)-1 7 | for left < right { 8 | // 正向遍历nums直到nums[left]为偶数,left>right 9 | // 找到排在最前面的偶数 10 | for left < right && nums[left]%2 == 1 { 11 | left++ 12 | } 13 | // 逆向遍历nums直到nums[right]]为奇数,left>right 14 | // 找到排在最后的奇数 15 | for left < right && nums[right]%2 == 0 { 16 | right-- 17 | } 18 | // 交换偶数和奇数 19 | nums[left], nums[right] = nums[right], nums[left] 20 | } 21 | return nums 22 | } 23 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/22.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | // https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/ 4 | /* 5 | 快指针先走k步,此时快慢指针间距为k 6 | 然后快慢指针一起走,等到快指针结束时慢指针距离链表尾部刚好是k 7 | */ 8 | func getKthFromEnd(head *ListNode, k int) *ListNode { 9 | 10 | fast, slow := head, head 11 | for i := 0; i < k; i++ { 12 | fast = fast.Next 13 | } 14 | for fast != nil { 15 | fast = fast.Next 16 | slow = slow.Next 17 | } 18 | return slow 19 | } 20 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/24.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | // https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/ 4 | /* 5 | 反转链表 将当前节点的next指向前一个节点即可,所以需要存储前一个节点 6 | */ 7 | func reverseList(head *ListNode) *ListNode { 8 | var ( 9 | prev *ListNode 10 | curr = head 11 | ) 12 | for curr != nil { 13 | next := curr.Next 14 | curr.Next = prev 15 | prev = curr 16 | curr = next 17 | } 18 | return prev 19 | } 20 | func reverseList2(head *ListNode) *ListNode { 21 | if head == nil || head.Next == nil { 22 | return head 23 | } 24 | newHead := reverseList2(head.Next) 25 | head.Next.Next = head 26 | head.Next = nil 27 | return newHead 28 | } 29 | -------------------------------------------------------------------------------- /algorithm/leetcode/lcof/model.go: -------------------------------------------------------------------------------- 1 | package lcof 2 | 3 | // Definition for singly-linked list. 4 | type ListNode struct { 5 | Val int 6 | Next *ListNode 7 | } 8 | 9 | // Definition for a binary tree node. 10 | type TreeNode struct { 11 | Val int 12 | Left *TreeNode 13 | Right *TreeNode 14 | } 15 | -------------------------------------------------------------------------------- /algorithm/leetcode/linkedlist/middle/detect_cycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lixd/i-go/d2d1491693f31efa867c5132765bbe4e693f25dc/algorithm/leetcode/linkedlist/middle/detect_cycle.png -------------------------------------------------------------------------------- /algorithm/leetcode/linkedlist/simple/delete_node.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | 面试题 02.03. 删除中间节点 5 | 实现一种算法,删除单向链表中间的某个节点(即不是第一个或最后一个节点),假定你只能访问该节点。 6 | 输入:单向链表a->b->c->d->e->f中的节点c 7 | 结果:不返回任何数据,但该链表变为a->b->d->e->f 8 | 9 | 只能访问该节点则不能通过将prev.next指向当前节点.next来实现 10 | 则把下一节点值赋值给当前节点 然后把当前节点的下一节点换成下下个节点。 11 | */ 12 | func main() { 13 | 14 | } 15 | 16 | // 4ms 2.9M内存 17 | func deleteNode(node *ListNode) { 18 | *node = *node.Next 19 | } 20 | 21 | // 0ms 2.9M内存 22 | func deleteNode2(node *ListNode) { 23 | node.Val = node.Next.Val 24 | node.Next = node.Next.Next 25 | } 26 | -------------------------------------------------------------------------------- /algorithm/leetcode/linkedlist/simple/kth_to_last.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | 5 | } 6 | 7 | //Definition for singly-linked list. 8 | //type ListNode struct { 9 | // Val int 10 | // Next *ListNode 11 | //} 12 | /* 13 | 快慢双指针。 14 | 快指针先动,领先慢指针k个长度。 15 | 快指针到头的时候慢指针刚好在倒数K个 16 | */ 17 | func kthToLast(head *ListNode, k int) int { 18 | fast := head 19 | slow := head 20 | for k > 0 { 21 | fast = fast.Next 22 | k-- 23 | } 24 | for fast != nil { 25 | slow = slow.Next 26 | fast = fast.Next 27 | } 28 | return slow.Val 29 | } 30 | -------------------------------------------------------------------------------- /algorithm/leetcode/matrix/middle/rotate.go: -------------------------------------------------------------------------------- 1 | package middle 2 | 3 | /* 4 | 面试题 01.07. 旋转矩阵 5 | */ 6 | func main() { 7 | //var matrix [][]int{[]int{1,2,3},[]{4,5,6},[]int{7,8,9}} 8 | //rotate(matrix) 9 | //fmt.Println(matrix) 10 | } 11 | func rotate(matrix [][]int) { 12 | 13 | for i := 0; i < len(matrix)/2; i++ { 14 | matrix[i], matrix[len(matrix)-1-i] = matrix[len(matrix)-1-i], matrix[i] 15 | } 16 | 17 | for i := 0; i < len(matrix); i++ { 18 | for j := 0; j < i; j++ { 19 | matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j] 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /algorithm/leetcode/number/3.go: -------------------------------------------------------------------------------- 1 | package number 2 | 3 | func lengthOfLongestSubstring(s string) int { 4 | var m = make(map[byte]int) 5 | var left, right, ans int 6 | for left <= right && right < len(s) { 7 | if m[s[right]] != 0 { // 遇到重复时移动left,具体移动位置由map记录 8 | left = max(left, m[s[right]]) 9 | } 10 | m[s[right]] = right + 1 // 记录下次遇到s[i]时left需要更新到的位置,所以是+1 11 | ans = max(ans, right-left+1) 12 | right++ 13 | } 14 | return ans 15 | } 16 | 17 | func max(a, b int) int { 18 | if a > b { 19 | return a 20 | } 21 | return b 22 | } 23 | -------------------------------------------------------------------------------- /algorithm/leetcode/number/3_test.go: -------------------------------------------------------------------------------- 1 | package number 2 | 3 | import "testing" 4 | 5 | func Test_lengthOfLongestSubstring(t *testing.T) { 6 | type args struct { 7 | s string 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want int 13 | }{ 14 | {name: "1", args: args{s: "abb"}, want: 2}, 15 | {name: "", args: args{s: " "}, want: 1}, 16 | } 17 | for _, tt := range tests { 18 | t.Run(tt.name, func(t *testing.T) { 19 | if got := lengthOfLongestSubstring(tt.args.s); got != tt.want { 20 | t.Errorf("lengthOfLongestSubstring() = %v, want %v", got, tt.want) 21 | } 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /algorithm/leetcode/string/simple/is_fliped_string.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | /* 9 | 面试题 01.09. 字符串轮转 10 | 字符串轮转。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottle是erbottlewat旋转后的字符串) 11 | 输入:s1 = "waterbottle", s2 = "erbottlewat" 12 | 输出:True 13 | 旋转体的两倍必然包含另一个旋转体 14 | */ 15 | func main() { 16 | s1 := "waterbottle" 17 | s2 := "erbottlewat" 18 | fmt.Println(isFlipedString(s1, s2)) 19 | } 20 | func isFlipedString(s1 string, s2 string) bool { 21 | if len(s1) != len(s2) { 22 | return false 23 | } 24 | return strings.Contains(s2+s2, s1) 25 | } 26 | -------------------------------------------------------------------------------- /algorithm/leetcode/string/simple/is_unique.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | /* 8 | 面试题 01.01. 判定字符是否唯一 9 | 实现一个算法,确定一个字符串 s 的所有字符是否全都不同。 10 | 11 | 示例 1: 12 | 13 | 输入: s = "leetcode" 14 | 输出: false 15 | 示例 2: 16 | 17 | 输入: s = "abc" 18 | 输出: true 19 | 限制: 20 | 21 | 0 <= len(s) <= 100 22 | 如果你不使用额外的数据结构,会很加分。 23 | 24 | */ 25 | func main() { 26 | astr := "leetcode" 27 | fmt.Println(isUnique(astr)) 28 | } 29 | 30 | func isUnique(astr string) bool { 31 | var m = make(map[int32]bool) 32 | arr := []rune(astr) 33 | for i := 0; i < len(arr); i++ { 34 | if _, ok := m[arr[i]]; ok { 35 | return false 36 | } 37 | m[arr[i]] = true 38 | } 39 | return true 40 | } 41 | -------------------------------------------------------------------------------- /algorithm/leetcode/tree/difficult/common.go: -------------------------------------------------------------------------------- 1 | package difficult 2 | 3 | //Definition for a binary tree node. 4 | type TreeNode struct { 5 | Val int 6 | Left *TreeNode 7 | Right *TreeNode 8 | } 9 | -------------------------------------------------------------------------------- /algorithm/leetcode/tree/difficult/max_path_sum_test.go: -------------------------------------------------------------------------------- 1 | package difficult 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func Test_maxPathSum(t *testing.T) { 9 | root := &TreeNode{ 10 | Val: 2, 11 | } 12 | root.Left = &TreeNode{ 13 | Val: -1, 14 | } 15 | //root.Right=&TreeNode{ 16 | // Val: 2, 17 | // Left: nil, 18 | // Right: &TreeNode{ 19 | // Val: 3, 20 | // Left: &TreeNode{ 21 | // Val: 1, 22 | // }, 23 | // }, 24 | //} 25 | fmt.Println(maxPathSum(root)) 26 | } 27 | -------------------------------------------------------------------------------- /algorithm/leetcode/tree/medium/04.03-list-of-depth-lcci_test.go: -------------------------------------------------------------------------------- 1 | package medium 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func Test_listOfDepth(t *testing.T) { 9 | root := &TreeNode{ 10 | Val: 1, 11 | Left: &TreeNode{ 12 | Val: 2, 13 | Left: &TreeNode{ 14 | Val: 4, 15 | Left: &TreeNode{ 16 | Val: 8, 17 | }, 18 | }, 19 | Right: &TreeNode{ 20 | Val: 5, 21 | }, 22 | }, 23 | Right: &TreeNode{ 24 | Val: 3, 25 | Right: &TreeNode{ 26 | Val: 7, 27 | }, 28 | }, 29 | } 30 | ret := listOfDepth(root) 31 | fmt.Println(ret) 32 | } 33 | -------------------------------------------------------------------------------- /algorithm/leetcode/tree/medium/95_test.go: -------------------------------------------------------------------------------- 1 | package medium 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestGenerateTrees2(t *testing.T) { 9 | trees := generateTrees(5) 10 | fmt.Println(trees) 11 | } 12 | -------------------------------------------------------------------------------- /algorithm/leetcode/tree/medium/98.go: -------------------------------------------------------------------------------- 1 | package medium 2 | 3 | import "math" 4 | 5 | func isValidBST(root *TreeNode) bool { 6 | return isValid(root, math.MinInt64, math.MaxInt64) 7 | } 8 | 9 | // 不能直接递归判断左右子树是否是BST 10 | func isValid(root *TreeNode, lower, upper int) bool { 11 | // terminator 12 | if root == nil { 13 | return true 14 | } 15 | // 判断当前节点是否满足条件 16 | if root.Val <= lower || root.Val >= upper { 17 | return false 18 | } 19 | // drill down 继续判断左右子树 20 | return isValid(root.Left, lower, root.Val) && isValid(root.Right, root.Val, upper) 21 | } 22 | -------------------------------------------------------------------------------- /algorithm/leetcode/tree/medium/common.go: -------------------------------------------------------------------------------- 1 | package medium 2 | 3 | // Definition for a binary tree node. 4 | type TreeNode struct { 5 | Val int 6 | Left *TreeNode 7 | Right *TreeNode 8 | } 9 | 10 | // Definition for singly-linked list. 11 | type ListNode struct { 12 | Val int 13 | Next *ListNode 14 | } 15 | -------------------------------------------------------------------------------- /algorithm/leetcode/tree/simple/100.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | func isSameTree(p *TreeNode, q *TreeNode) bool { 4 | return isSame(p, q) 5 | } 6 | 7 | // BFS 8 | func isSame(p *TreeNode, q *TreeNode) bool { 9 | // terminator 10 | if p == nil && q == nil { 11 | return true 12 | } 13 | if p == nil || q == nil { 14 | return false 15 | } 16 | // process 17 | if p.Val != q.Val { 18 | return false 19 | } 20 | // drill down 21 | return isSame(p.Left, q.Left) && isSame(p.Right, q.Right) 22 | } 23 | -------------------------------------------------------------------------------- /algorithm/leetcode/tree/simple/101.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | func isSymmetric(root *TreeNode) bool { 4 | return symmetric(root, root) 5 | } 6 | 7 | func symmetric(x, y *TreeNode) bool { 8 | // 如果两个子树都为空指针,则它们相等或对称 9 | if x == nil && y == nil { 10 | return true 11 | } 12 | // 如果两个子树只有一个为空指针,则它们不相等或不对称 13 | if x == nil || y == nil { 14 | return false 15 | } 16 | // 如果两个子树根节点的值不相等,则它们不相等或不对称 17 | if x.Val != y.Val { 18 | return false 19 | } 20 | return symmetric(x.Left, y.Right) && symmetric(x.Right, y.Left) 21 | } 22 | -------------------------------------------------------------------------------- /algorithm/leetcode/tree/simple/104.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | func maxDepth(root *TreeNode) int { 4 | return dfs(root) 5 | } 6 | 7 | func dfs(root *TreeNode) int { 8 | var val int 9 | if root == nil { 10 | return 0 11 | } 12 | // root 节点算一层 13 | val++ 14 | // 然后加上左子树右子树中最大的层级 就是总层数 15 | left := dfs(root.Left) 16 | right := dfs(root.Right) 17 | val += max(left, right) 18 | return val 19 | } 20 | 21 | func max(a, b int) int { 22 | if a > b { 23 | return a 24 | } 25 | return b 26 | } 27 | -------------------------------------------------------------------------------- /algorithm/leetcode/tree/simple/104_test.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func Test_maxDepth(t *testing.T) { 9 | root := &TreeNode{} 10 | root.Left = &TreeNode{ 11 | Val: 1, 12 | } 13 | root.Right = &TreeNode{ 14 | Val: 2, 15 | Left: nil, 16 | Right: &TreeNode{ 17 | Val: 3, 18 | }, 19 | } 20 | fmt.Println(maxDepth(root)) 21 | } 22 | -------------------------------------------------------------------------------- /algorithm/leetcode/tree/simple/common.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | // Definition for a binary tree node. 4 | type TreeNode struct { 5 | Val int 6 | Left *TreeNode 7 | Right *TreeNode 8 | } 9 | -------------------------------------------------------------------------------- /algorithm/leetcode/tree/simple/is_balanced_test.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func Test_isBalanced(t *testing.T) { 9 | root := &TreeNode{} 10 | root.Left = &TreeNode{ 11 | Val: 1, 12 | } 13 | root.Right = &TreeNode{ 14 | Val: 2, 15 | Left: nil, 16 | Right: &TreeNode{ 17 | Val: 3, 18 | Left: &TreeNode{ 19 | Val: 1, 20 | }, 21 | }, 22 | } 23 | fmt.Println(isBalanced(root)) 24 | } 25 | -------------------------------------------------------------------------------- /algorithm/others/hyperloglog_test.go: -------------------------------------------------------------------------------- 1 | package others 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sirupsen/logrus" 7 | ) 8 | 9 | func TestHyper(t *testing.T) { 10 | hyperLL := NewHyperLL() 11 | isExits := hyperLL.PFAdd("first") 12 | logrus.Info(isExits) 13 | isExits = hyperLL.PFAdd("first") 14 | logrus.Info(isExits) 15 | } 16 | -------------------------------------------------------------------------------- /algorithm/similarity/t/similarity_test.go: -------------------------------------------------------------------------------- 1 | package t 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestCosineSimilar(t *testing.T) { 8 | Similar() 9 | } 10 | -------------------------------------------------------------------------------- /algorithm/sort/bubble_sort.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | // BubbleSort 冒泡排序 4 | /* 5 | 时间复杂度: O(n^2) 6 | 空间复杂度: O(1) 原地排序 7 | 稳定性:稳定 8 | 是否基于比较: 是 9 | 思想: 双重 for loop 比较并交换位置,外层for loop 每完成一次都会排序好一个数字 10 | 优化1: 增加标志位 flag 在第i次排序如果没有元素交换(说明已经完成排序),则不进行第i+1次排序 11 | 优化2: TODO 12 | */ 13 | func BubbleSort(arr []int) []int { 14 | for i := 0; i < len(arr); i++ { 15 | flag := false 16 | for j := i; j < len(arr)-1; j++ { 17 | if arr[j] > arr[j+1] { 18 | arr[j], arr[j+1] = arr[j+1], arr[j] 19 | flag = true 20 | } 21 | } 22 | if !flag { 23 | break 24 | } 25 | } 26 | return arr 27 | } 28 | -------------------------------------------------------------------------------- /algorithm/sort/quicksort_test.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func Test_quickSort(t *testing.T) { 9 | arr := []int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10} 10 | sort := quickSort2(arr) 11 | fmt.Println("before:", arr) 12 | fmt.Println("after:", sort) 13 | } 14 | 15 | // 1143 ns/op 16 | func BenchmarkQuickSort(b *testing.B) { 17 | arr := []int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10} 18 | for i := 0; i < b.N; i++ { 19 | quickSort(arr) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /apm/logging/cerebro.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | # cerebro 是一个简单的 ES 监控工具 4 | cerebro: 5 | image: lmenezes/cerebro:0.9.2 6 | container_name: cerebro 7 | restart: always 8 | ports: 9 | - "9000:9000" 10 | command: 11 | - -Dhosts.0.host=http://elk-es:9200 12 | 13 | networks: 14 | default: 15 | external: 16 | name: elk 17 | -------------------------------------------------------------------------------- /apm/logging/esexporter.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | # es metric 采集 4 | elasticsearch_exporter: 5 | image: justwatch/elasticsearch_exporter:1.1.0 6 | command: 7 | - '--es.uri=http://elk-es:9200' 8 | restart: always 9 | ports: 10 | - 9114:9114 11 | 12 | networks: 13 | default: 14 | external: 15 | name: elk 16 | -------------------------------------------------------------------------------- /apm/logging/filebeat.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | # filebeat 从文件中读取日志并发送给 Logstash 4 | filebeat: 5 | image: elastic/filebeat:7.8.0 6 | container_name: elk-filebeat 7 | restart: always 8 | volumes: 9 | # 将宿主机目录隐射到容器中 10 | - /var/logs:/var/logs 11 | # 指定配置文件 12 | - ./filebeat.conf.yml:/usr/share/filebeat/filebeat.yml 13 | - ./logs:/usr/share/filebeat/logs 14 | - ./data:/usr/share/filebeat/data 15 | networks: 16 | default: 17 | external: 18 | name: elk 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /apm/logging/kibana.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | # kibana 方便观察es中的数据 4 | kibana: 5 | image: kibana:7.8.0 6 | container_name: elk-kibana 7 | restart: always 8 | environment: 9 | SERVER_NAME: kibana.local 10 | ELASTICSEARCH_HOSTS: http://elk-es:9200 11 | I18N_LOCALE: zh-en 12 | ports: 13 | - 5602:5601 14 | 15 | networks: 16 | default: 17 | external: 18 | name: elk 19 | -------------------------------------------------------------------------------- /apm/logging/logstash.conf: -------------------------------------------------------------------------------- 1 | input { 2 | # 来源beats 3 | beats { 4 | # 端口 5 | port => "5044" 6 | } 7 | } 8 | # 分析、过滤插件,可以多个 9 | filter { 10 | grok { 11 | # 将日志内容存储到 Message 字段中 12 | match => { "message" => "%{COMBINEDAPACHELOG}"} 13 | } 14 | geoip { 15 | # 将客户端IP存储到 clientip 字段 16 | source => "clientip" 17 | } 18 | } 19 | output { 20 | # 选择elasticsearch 21 | elasticsearch { 22 | hosts => ["http://elk-es:9200"] 23 | # {fields} {service} 来自于 filebeat.conf 可以自定义字段名 24 | # {@metadata} {version} 则是自带属性 25 | index => "%{[fields][service]}-%{[@metadata][version]}-%{+YYYY.MM.dd}" 26 | } 27 | } -------------------------------------------------------------------------------- /apm/logging/logstash.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | logstash: 4 | image: logstash:7.8.0 5 | container_name: elk-logstash 6 | restart: always 7 | volumes: 8 | # 指定管道配置文件 9 | - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf:rw 10 | environment: 11 | - elasticsearch.hosts=http://elk-es:9200 12 | - "LS_JAVA_OPTS=-Xmx256m -Xms256m" 13 | ports: 14 | - 5044:5044 15 | 16 | networks: 17 | default: 18 | external: 19 | name: elk 20 | -------------------------------------------------------------------------------- /apm/logging/t.go: -------------------------------------------------------------------------------- 1 | package logging 2 | 3 | func main() { 4 | // https://blog.csdn.net/github_35780607/article/details/109514307 5 | // 1.filebeat 采集数据 从日志文件中读取日志并发送到 logstash 6 | // 2.logstash 对日志进行过滤整合等操作然后写入es 7 | // 3.es 存储采集的日志数据 8 | // 4.kibana UI 9 | } 10 | -------------------------------------------------------------------------------- /apm/prometheus/cadvisor.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | # cadvisor 容器状态监控 4 | cadvisor: 5 | image: google/cadvisor:latest 6 | container_name: cadvisor 7 | ports: 8 | - 8090:8080 9 | volumes: 10 | - /:/rootfs:ro 11 | - /var/run:/var/run:rw 12 | - /sys:/sys:ro 13 | - /var/lib/docker/:/var/lib/docker:ro 14 | 15 | networks: 16 | default: 17 | external: 18 | name: prometheus 19 | -------------------------------------------------------------------------------- /apm/prometheus/grafana.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | grafana: 4 | image: grafana/grafana 5 | container_name: grafana 6 | restart: always 7 | ports: 8 | - "3000:3000" 9 | networks: 10 | default: 11 | external: 12 | name: prometheus 13 | 14 | # 默认账号密码都为admin 15 | -------------------------------------------------------------------------------- /apm/prometheus/node-exporter.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | # node-exporter 服务器状态监控 4 | node-exporter: 5 | image: prom/node-exporter 6 | restart: always 7 | container_name: node-exporter 8 | ports: 9 | - 9101:9100 10 | 11 | networks: 12 | default: 13 | external: 14 | name: prometheus 15 | -------------------------------------------------------------------------------- /apm/trace/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # jaeger all-in-one 2 | version: '3.2' 3 | services: 4 | db: 5 | image: jaegertracing/all-in-one 6 | container_name: jaeger-all-in-one 7 | restart: always 8 | ports: 9 | - 5775:5775/udp 10 | - 6831:6831/udp 11 | - 6832:6832/udp 12 | - 5778:5778 13 | - 16686:16686 14 | - 14268:14268 15 | - 14269:14269 16 | -------------------------------------------------------------------------------- /apm/trace/gin/cmd/gin.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:8080/ping 2 | Accept: application/json 3 | 4 | 5 | -------------------------------------------------------------------------------- /apm/trace/grpc/proto/hello/proto/hello.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helloworld; 3 | 4 | service Hello { 5 | rpc SayHello (HelloReq) returns (HelloRep) { 6 | } 7 | } 8 | 9 | message HelloReq { 10 | string name = 1; 11 | } 12 | 13 | message HelloRep { 14 | string message = 1; 15 | } 16 | -------------------------------------------------------------------------------- /apm/trace/jaeger-agent.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | # jaeger-agent 单独部署到各个需要采集的机器上 4 | jaeger-agent: 5 | image: jaegertracing/jaeger-agent 6 | container_name: jaeger-agent 7 | environment: 8 | - REPORTER_GRPC_HOST_PORT=jaeger-collector:14250 9 | - LOG_LEVEL=debug 10 | ports: 11 | - 5775:5775/udp 12 | - 5778:5778 13 | - 6831:6831/udp 14 | - 6832:6832/udp 15 | - 14271:14271 16 | 17 | networks: 18 | default: 19 | external: 20 | name: jaeger 21 | 22 | -------------------------------------------------------------------------------- /apm/trace/jaeger-es.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | # elasticsearch jaeger存储后端 单独部署 4 | elasticsearch: 5 | image: docker.elastic.co/elasticsearch/elasticsearch:7.8.0 6 | container_name: jaeger-es 7 | environment: 8 | - discovery.type=single-node 9 | # 开启内存锁定 10 | - bootstrap.memory_lock=true 11 | - "ES_JAVA_OPTS=-Xms512m -Xmx512m" 12 | ulimits: 13 | memlock: 14 | soft: -1 15 | hard: -1 16 | volumes: 17 | - ./data:/usr/share/elasticsearch/data 18 | - ./logs:/usr/share/elasticsearch/logs 19 | ports: 20 | - 9201:9200 21 | 22 | networks: 23 | default: 24 | external: 25 | name: jaeger 26 | -------------------------------------------------------------------------------- /apm/trace/kibana.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | # kibana 方便观察es中的数据 4 | kibana: 5 | image: 'kibana:7.8.0' 6 | container_name: jaeger-kibana 7 | environment: 8 | SERVER_NAME: kibana.local 9 | ELASTICSEARCH_HOSTS: http://jaeger-es:9200 10 | I18N_LOCALE: zh-en 11 | ports: 12 | - 5602:5601 13 | 14 | networks: 15 | default: 16 | external: 17 | name: jaeger 18 | -------------------------------------------------------------------------------- /apm/trace/lesson1/build.bat: -------------------------------------------------------------------------------- 1 | SET CGO_ENABLED=0 2 | SET GOOS=linux 3 | SET GOARCH=amd64 4 | go build -ldflags="-s -w" hello.go 5 | -------------------------------------------------------------------------------- /cgo/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | typedef int (*intFunc) (); 5 | 6 | int 7 | bridge_int_func(intFunc f) 8 | { 9 | return f(); 10 | } 11 | 12 | int fortytwo() 13 | { 14 | return 42; 15 | } 16 | */ 17 | import "C" 18 | import "fmt" 19 | 20 | func main() { 21 | f := C.intFunc(C.fortytwo) 22 | fmt.Println(int(C.bridge_int_func(f))) 23 | } 24 | -------------------------------------------------------------------------------- /cgo/fork.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | // 测试fork调用 4 | int main(void){ 5 | pid_t pid; 6 | pid=fork(); 7 | if(pid==0) { 8 | printf("child process\n"); 9 | printf("child pid is %d\n",getpid()); 10 | printf("child ppid is %d\n",getppid()); 11 | } else if(pid>0) { 12 | printf("parent process\n"); 13 | printf("parent pid is %d\n",getpid()); 14 | printf("parent ppid is %d\n",getppid()); 15 | }else { 16 | printf("fork error\n"); 17 | } 18 | return 0; 19 | } 20 | // gcc -o fork fork.c 21 | // man fork 22 | -------------------------------------------------------------------------------- /cgo/fork3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | int main(void){ 6 | pid_t pid; 7 | int n=0,m=30; 8 | // 主进程一直fork子进程,直到子进程达到1W个 9 | while(1){ 10 | pid=fork(); 11 | if(pid==0){ 12 | break; 13 | } 14 | else if(pid>0){ 15 | printf(" %d\n",n++); 16 | if (n>10000){ // 限制最多运行10000个进程 17 | break; 18 | } 19 | } 20 | else{ 21 | exit(1); 22 | } 23 | } 24 | // 子进程休眠30秒后退出 25 | while(m--){ 26 | printf("sleep %d\n",m); 27 | sleep(1); 28 | } 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /cgo/hello.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | #include 5 | */ 6 | import "C" 7 | 8 | func main() { 9 | C.puts(C.CString("Hello, World\n")) 10 | } 11 | -------------------------------------------------------------------------------- /cgo/helloworld.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | char *str = "Hello, World\n"; 5 | printf("%s", str); 6 | return 0; 7 | } 8 | // 编译 9 | // gcc -o helloworld helloworld.c 10 | -------------------------------------------------------------------------------- /cgo/helloworld.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("Hello World") 7 | } 8 | -------------------------------------------------------------------------------- /cgo/helloworld.s: -------------------------------------------------------------------------------- 1 | .section .data # 数据段 2 | msg: 3 | .ascii "Hello, World\n" 4 | .section .text # 代码段 5 | .global _start # 全局开始函数,必须是 _start 6 | 7 | _start: 8 | movl $13, %edx # 系统调用 write 的第 3 个参数为 13 9 | movl $msg, %ecx # 第 2 个参数是 Hello World\n 10 | movl $1, %ebx # 第 1 个参数是 1,标准输出的编号 11 | movl $4, %eax # sys_write 系统调用的编号是 4 12 | int $0x80 13 | 14 | movl $0, %ebx # exit 系统调用的第一个参数,即 exit(0) 15 | movl $1, %eax # sys_exit 编号为 1 16 | int $0x80 # 调用 exit,退出程序 17 | 18 | # 从 Hello World 来看看 Go 的运行流程 https://shimo.im/docs/HQHVVYhdGxycdVwX 19 | # 系统调用实现:将要调用的系统调用编号存到exa寄存器,然后触发0x80指令即可,对应参数则到相应寄存器 20 | # 编译链接 21 | # as -o helloworld.o helloworld.s 22 | # ld -o helloworld helloworld.o 23 | -------------------------------------------------------------------------------- /cloud-natinve/clientgo/key.go: -------------------------------------------------------------------------------- 1 | package clientgo 2 | 3 | const KubeConfig = "D:\\Home\\17x\\Projects\\i-go\\cloud-natinve\\clientgo\\kubeconfig" 4 | -------------------------------------------------------------------------------- /cloud-natinve/cobra-demo/cmd/hello.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/pkg/errors" 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | var cmd = &cobra.Command{ 11 | Short: "hello", 12 | Args: func(cmd *cobra.Command, args []string) error { 13 | if len(args) < 1 { 14 | return errors.New("requires at least one arg") 15 | } 16 | if isValidColor(args[0]) { 17 | return nil 18 | } 19 | return fmt.Errorf("invalid color specified: %s", args[0]) 20 | }, 21 | Run: func(cmd *cobra.Command, args []string) { 22 | fmt.Println("Hello, World!") 23 | }, 24 | } 25 | 26 | func isValidColor(color string) bool { 27 | return color == "green" 28 | } 29 | -------------------------------------------------------------------------------- /cloud-natinve/cobra-demo/cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | func init() { 10 | rootCmd.AddCommand(versionCmd) 11 | } 12 | 13 | var versionCmd = &cobra.Command{ 14 | Use: "version", 15 | Short: "Print the version number of Hugo", 16 | Long: `All software has versions. This is Hugo's`, 17 | Run: func(cmd *cobra.Command, args []string) { 18 | fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /cloud-natinve/cobra-demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "i-go/cloud-natinve/cobra-demo/cmd" 5 | ) 6 | 7 | func main() { 8 | cmd.Execute() 9 | } 10 | -------------------------------------------------------------------------------- /cloud-natinve/tunnel/ssh/cfgutil/json.go: -------------------------------------------------------------------------------- 1 | package cfgutil 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "io" 7 | "io/ioutil" 8 | "os" 9 | ) 10 | 11 | var ( 12 | // ErrInvalidJSONFormat . 13 | ErrInvalidJSONFormat = errors.New("invalid json format") 14 | ) 15 | 16 | // LoadJSON . 17 | func LoadJSON(reader io.Reader, recv interface{}) error { 18 | byts, err := ioutil.ReadAll(reader) 19 | if err != nil { 20 | return err 21 | } 22 | 23 | if !json.Valid(byts) { 24 | return ErrInvalidJSONFormat 25 | } 26 | 27 | return json.Unmarshal(byts, recv) 28 | } 29 | 30 | // Open . 31 | func Open(fp string) (io.ReadCloser, error) { 32 | return os.OpenFile(fp, os.O_RDONLY, 0644) 33 | } 34 | -------------------------------------------------------------------------------- /cloud-natinve/tunnel/ssh/helper/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "ssh": { 3 | "host": "172.20.149.53", 4 | "user": "root", 5 | "secret": "root", 6 | "port": 22 7 | }, 8 | "tunnels": [ 9 | { 10 | "ident": "hello", 11 | "localPort": 50051, 12 | "remoteHost": "192.168.10.193", 13 | "remotePort": 50051 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /cloud-natinve/tunnel/ssh/helper/ssh.go: -------------------------------------------------------------------------------- 1 | package main 2 | -------------------------------------------------------------------------------- /cloud-natinve/tunnel/tcpforwarder/chiselwatcher/config.yaml: -------------------------------------------------------------------------------- 1 | hosts: 2 | # 主机名,需要能免密登录 3 | kc-agent1: 4 | # 隧道名 5 | nats: 6 | local: 9889 7 | remote: 9889 8 | staticServer: 9 | local: 8081 10 | remote: 8081 11 | -------------------------------------------------------------------------------- /core/conf/t/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "i-go/core/conf" 5 | ) 6 | 7 | func main() { 8 | path1 := "conf/api/elasticsearch.yaml" 9 | path2 := "conf/api/mongodb.yaml" 10 | conf.Loads([]string{path1, path2}) 11 | select {} 12 | } 13 | -------------------------------------------------------------------------------- /core/http/ret/code.go: -------------------------------------------------------------------------------- 1 | package ret 2 | 3 | import "net/http" 4 | 5 | const ( 6 | Success = http.StatusOK 7 | SuccessMsg = "success" 8 | 9 | Fail = http.StatusBadRequest 10 | FailMsg = "fail" 11 | BadRequest = "bad request" 12 | 13 | Unauthorized = http.StatusUnauthorized 14 | UnauthorizedMsg = "unauthorized" 15 | 16 | Forbidden = http.StatusForbidden 17 | ForbiddenMsg = "forbidden" 18 | 19 | Limit = http.StatusTooManyRequests 20 | LimitMsg = "too many requests" 21 | ) 22 | -------------------------------------------------------------------------------- /core/logger/zap_with_lumberjack_test.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | 7 | "go.uber.org/zap" 8 | ) 9 | 10 | func TestInitLogger(t *testing.T) { 11 | InitLogger() 12 | simpleHttpGet("https://www.vaptcha.com") 13 | } 14 | 15 | func simpleHttpGet(url string) { 16 | resp, err := http.Get(url) 17 | if err != nil { 18 | ILog.Error( 19 | "Error fetching url..", 20 | zap.String("url", url), 21 | zap.Error(err)) 22 | } else { 23 | ILog.Info("Success..", 24 | zap.String("statusCode", resp.Status), 25 | zap.String("url", url)) 26 | _ = resp.Body.Close() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /data/conf/api/README.md: -------------------------------------------------------------------------------- 1 | 由于需要将配置文件按组件拆分,所以这里在创建一层文件夹用于区分不同模块。 -------------------------------------------------------------------------------- /data/conf/api/elasticsearch.yaml: -------------------------------------------------------------------------------- 1 | # ElasticSearch 第三方 sdk 2 | elasticsearch: 3 | addr: "http://47.93.123.142:9201" 4 | username: "" 5 | password: "" -------------------------------------------------------------------------------- /data/conf/api/mongodb.yaml: -------------------------------------------------------------------------------- 1 | mongodb: 2 | appUrl: "47.93.123.142:5000" 3 | username: "test" 4 | password: "123456" 5 | maxPoolSize: 10 6 | dbs: 7 | test: "test" 8 | job: "job" 9 | x: "17x" 10 | # 默认 认证机制 11 | authMechanism: "SCRAM-SHA-1" -------------------------------------------------------------------------------- /data/conf/config_ip.yaml: -------------------------------------------------------------------------------- 1 | "endpoints": "http://192.168.3.3:2379,http://192.168.3.4:2379,http://192.168.3.5:2379" 2 | # 百度云链接 链接:https://pan.baidu.com/s/180__IJ11q0ng5IDYgwXE3A 提取码:6666 3 | # 仓库地址 https://github.com/lionsoul2014/ip2region/tree/master/data 4 | "region": "data/conf/data/ip2region.db" 5 | # 下载链接(需登录): https://www.maxmind.com/en/accounts/576594/geoip/downloads 6 | "geo": "data/conf/data/GeoLite2-City.mmdb" 7 | -------------------------------------------------------------------------------- /data/conf/data/README.md: -------------------------------------------------------------------------------- 1 | ip2region.db 下载 2 | # 百度云链接 链接:https://pan.baidu.com/s/180__IJ11q0ng5IDYgwXE3A 提取码:6666 3 | # 仓库地址 https://github.com/lionsoul2014/ip2region/tree/master/data 4 | GeoLite2-City.mmdb 下载 5 | # 下载链接(需登录): https://www.maxmind.com/en/accounts/576594/geoip/downloads 6 | -------------------------------------------------------------------------------- /data/conf/filename.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | // 各个组件对应的配置文件名 4 | const ( 5 | Elasticsearch = "elasticsearch" 6 | MongoDB = "mongodb" 7 | Redis = "redis" 8 | Basic = "basic" 9 | ) 10 | -------------------------------------------------------------------------------- /data/data.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "path/filepath" 5 | "runtime" 6 | ) 7 | 8 | // basepath is the root directory of this package. 9 | var basepath string 10 | 11 | func init() { 12 | _, currentFile, _, _ := runtime.Caller(0) 13 | basepath = filepath.Dir(currentFile) 14 | } 15 | 16 | // Path returns the absolute path the given relative file or directory path, 17 | func Path(rel string) string { 18 | if filepath.IsAbs(rel) { 19 | return rel 20 | } 21 | return filepath.Join(basepath, rel) 22 | } 23 | -------------------------------------------------------------------------------- /demo/account/dto/account.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | import "i-go/demo/cmodel" 4 | 5 | type AccountInsertReq struct { 6 | Id uint `json:"id" form:"id"` 7 | UserId uint `json:"userId" form:"userId"` 8 | Amount float64 `json:"amount" form:"amount"` 9 | } 10 | 11 | type AccountReq struct { 12 | AccountInsertReq 13 | cmodel.Page 14 | } 15 | 16 | type AccountList struct { 17 | Data []AccountResp `json:"data"` 18 | Page cmodel.Page `json:"page"` 19 | } 20 | 21 | type AccountResp struct { 22 | Id uint `json:"id"` 23 | UserId uint `json:"userId"` 24 | Amount float64 `json:"amount"` 25 | } 26 | -------------------------------------------------------------------------------- /demo/account/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "i-go/core/conf" 5 | "i-go/core/db/mysqldb" 6 | "i-go/core/logger" 7 | "i-go/demo/account/model" 8 | "i-go/demo/account/router" 9 | 10 | "github.com/gin-gonic/gin" 11 | ) 12 | 13 | func main() { 14 | Init() 15 | 16 | engine := gin.Default() 17 | gin.SetMode(gin.ReleaseMode) 18 | router.RegisterRouter(engine) 19 | if err := engine.Run(":8080"); err != nil { 20 | panic(err) 21 | } 22 | } 23 | 24 | // Init 初始化 25 | /* 26 | 读取配置文件 初始化数据库连接 27 | */ 28 | func Init() { 29 | conf.Load("D:/lillusory/projects/i-go/conf/config.yml") 30 | mysqldb.Init() 31 | mysqldb.MySQL.AutoMigrate(&model.Account{}) 32 | 33 | logger.InitLogger() 34 | } 35 | -------------------------------------------------------------------------------- /demo/account/model/account.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "gorm.io/gorm" 4 | 5 | type Account struct { 6 | gorm.Model 7 | UserId uint `gorm:"type:int;NOT NULL"` 8 | Amount float64 `gorm:"type:decimal(10,6)"` 9 | } 10 | -------------------------------------------------------------------------------- /demo/cmodel/common.go: -------------------------------------------------------------------------------- 1 | package cmodel 2 | -------------------------------------------------------------------------------- /demo/common/ret/code.go: -------------------------------------------------------------------------------- 1 | package ret 2 | 3 | const ( 4 | Success = 200 5 | SuccessMsg = "success" 6 | 7 | Fail = 400 8 | FailMsg = "fail" 9 | BadRequest = "bad request" 10 | 11 | Unauthorized = 401 12 | UnauthorizedMsg = "unauthorized" 13 | 14 | Forbidden = 403 15 | ForbiddenMsg = "forbidden" 16 | ) 17 | -------------------------------------------------------------------------------- /demo/common/ret/ctl/controller.go: -------------------------------------------------------------------------------- 1 | // Package ctl Controller层返回值 2 | package ctl 3 | 4 | import ( 5 | "net/http" 6 | 7 | "i-go/demo/common/ret/srv" 8 | 9 | "github.com/gin-gonic/gin" 10 | ) 11 | 12 | func BadRequest(c *gin.Context, msg string) { 13 | c.AbortWithStatusJSON(http.StatusOK, srv.BadRequest()) 14 | } 15 | 16 | func Unauthorized(c *gin.Context) { 17 | c.AbortWithStatusJSON(http.StatusOK, srv.Unauthorized()) 18 | } 19 | 20 | func Forbidden(c *gin.Context) { 21 | c.AbortWithStatusJSON(http.StatusOK, srv.Forbidden()) 22 | } 23 | 24 | func Success(c *gin.Context, result *srv.Result) { 25 | c.JSON(http.StatusOK, result) 26 | } 27 | -------------------------------------------------------------------------------- /demo/order/dto/order.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | import "i-go/demo/cmodel" 4 | 5 | type OrderReq struct { 6 | Id uint `json:"id" form:"id"` 7 | UserId uint `json:"userId" form:"userId"` 8 | Amount float64 `json:"amount" form:"amount"` 9 | cmodel.Page 10 | } 11 | 12 | type OrderList struct { 13 | Data []OrderResp `json:"data"` 14 | Page cmodel.Page `json:"page"` 15 | } 16 | type OrderResp struct { 17 | Id uint `json:"id"` 18 | UserId uint `json:"userId"` 19 | Amount float64 `json:"amount"` 20 | } 21 | -------------------------------------------------------------------------------- /demo/order/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "i-go/core/conf" 5 | "i-go/core/db/mysqldb" 6 | "i-go/core/logger" 7 | "i-go/demo/order/model" 8 | "i-go/demo/order/router" 9 | 10 | "github.com/gin-gonic/gin" 11 | ) 12 | 13 | func main() { 14 | Init() 15 | 16 | engine := gin.Default() 17 | gin.SetMode(gin.ReleaseMode) 18 | router.RegisterRouter(engine) 19 | if err := engine.Run(":8080"); err != nil { 20 | panic(err) 21 | } 22 | } 23 | 24 | // Init 初始化 25 | /* 26 | 读取配置文件 初始化数据库连接 27 | */ 28 | func Init() { 29 | conf.Load("D:/lillusory/projects/i-go/conf/config.yml") 30 | mysqldb.Init() 31 | mysqldb.MySQL.AutoMigrate(&model.Order{}) 32 | 33 | logger.InitLogger() 34 | } 35 | -------------------------------------------------------------------------------- /demo/order/model/order.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "gorm.io/gorm" 4 | 5 | type Order struct { 6 | gorm.Model 7 | UserId uint `gorm:"type:int;NOT NULL"` 8 | Amount float64 `gorm:"type:decimal(10,6)"` 9 | } 10 | -------------------------------------------------------------------------------- /demo/user/dto/user.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | import "i-go/demo/cmodel" 4 | 5 | type UserReq struct { 6 | ID uint `json:"id"` 7 | Name string `json:"name"` 8 | Phone string `json:"phone"` 9 | Pwd string `json:"pwd"` 10 | Age uint `json:"age"` 11 | RegisterIP string 12 | LoginIP string 13 | } 14 | 15 | type UserResp struct { 16 | ID uint `json:"id"` 17 | Name string `json:"name"` 18 | Phone string `json:"phone"` 19 | Age uint `json:"age"` 20 | Pwd string `json:"-"` 21 | } 22 | 23 | type UserList struct { 24 | Data []UserResp `json:"data"` 25 | Page cmodel.Page `json:"page"` 26 | } 27 | -------------------------------------------------------------------------------- /demo/user/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "i-go/core/conf" 5 | "i-go/core/db/mysqldb" 6 | "i-go/core/logger" 7 | "i-go/demo/user/model" 8 | "i-go/demo/user/router" 9 | 10 | "github.com/gin-gonic/gin" 11 | ) 12 | 13 | func main() { 14 | Init() 15 | 16 | engine := gin.Default() 17 | gin.SetMode(gin.ReleaseMode) 18 | router.RegisterRouter(engine) 19 | if err := engine.Run(":8080"); err != nil { 20 | panic(err) 21 | } 22 | } 23 | 24 | // Init 初始化 25 | /* 26 | 读取配置文件 初始化数据库连接 27 | */ 28 | func Init() { 29 | conf.Load("D:/lillusory/projects/i-go/conf/config.yml") 30 | mysqldb.Init() 31 | mysqldb.MySQL.AutoMigrate(&model.User{}) 32 | 33 | logger.InitLogger() 34 | } 35 | -------------------------------------------------------------------------------- /demo/user/model/model.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | ) 6 | 7 | type User struct { 8 | gorm.Model 9 | Name string `gorm:"type:varchar(16);"` 10 | Pwd string `gorm:"type:varchar(16);NOT NULL"` 11 | Phone string `gorm:"type:varchar(20);NOT NULL"` 12 | Age uint `gorm:"type:tinyint;"` 13 | RegisterIP string `gorm:"type:varchar(64);"` 14 | LoginIP string `gorm:"type:varchar(64);"` 15 | } 16 | -------------------------------------------------------------------------------- /demo/validate/check.go: -------------------------------------------------------------------------------- 1 | package validate 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | "unicode" 7 | ) 8 | 9 | // Phone 电话校验 10 | func Phone(phone string) bool { 11 | matched, err := regexp.MatchString("^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$", phone) 12 | if err != nil { 13 | fmt.Println(err) 14 | } 15 | return matched 16 | } 17 | 18 | // IsNumbers 字符串是否全为数字 19 | func IsNumbers(keyWords string) bool { 20 | for _, v := range keyWords { 21 | isNumber := unicode.IsNumber(v) 22 | if !isNumber { 23 | return false 24 | } 25 | } 26 | return true 27 | } 28 | -------------------------------------------------------------------------------- /desing-pattern/goadvanced/README.md: -------------------------------------------------------------------------------- 1 | 《Go高级编程》中的部分示例 2 | -------------------------------------------------------------------------------- /desing-pattern/goadvanced/code.go: -------------------------------------------------------------------------------- 1 | package goadvanced 2 | 3 | func Random(n int64) <-chan int64 { 4 | ch := make(chan int64) 5 | go func() { 6 | defer close(ch) 7 | for i := int64(0); i < n; i++ { 8 | select { 9 | case ch <- 0: 10 | case ch <- 1: 11 | } 12 | } 13 | }() 14 | return ch 15 | } 16 | -------------------------------------------------------------------------------- /desing-pattern/goadvanced/code_test.go: -------------------------------------------------------------------------------- 1 | package goadvanced 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestRandom(t *testing.T) { 9 | ch := Random(10) 10 | for v := range ch { 11 | fmt.Print(v) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /desing-pattern/goadvanced/params.go: -------------------------------------------------------------------------------- 1 | package goadvanced 2 | 3 | import "fmt" 4 | 5 | func Print(a ...interface{}) { 6 | fmt.Println(a...) 7 | } 8 | -------------------------------------------------------------------------------- /desing-pattern/goadvanced/params_test.go: -------------------------------------------------------------------------------- 1 | package goadvanced 2 | 3 | import "testing" 4 | 5 | func TestPrint(t *testing.T) { 6 | a := []interface{}{"123", "abc"} 7 | Print(a) // [123 abc] 等价于 Print([]interface{}{"123", "abc"}) 8 | Print([]interface{}{"123", "abc"}) 9 | Print(a...) // 123 abc 等价于 Print("123","abc") 10 | Print("123", "abc") 11 | } 12 | -------------------------------------------------------------------------------- /desing-pattern/goadvanced/rand_test.go: -------------------------------------------------------------------------------- 1 | package goadvanced 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "testing" 7 | ) 8 | 9 | func TestRand(t *testing.T) { 10 | p := rand.Perm(10) // 生成一个伪随机切片 11 | fmt.Printf("perm: %+v\n", p) 12 | a := make([]int, 0, 10) 13 | for i := 0; i < 10; i++ { 14 | a = append(a, i) 15 | } 16 | rand.Shuffle(len(a), func(i, j int) { // 洗牌 17 | a[i], a[j] = a[j], a[i] 18 | }) 19 | fmt.Println(a) 20 | } 21 | -------------------------------------------------------------------------------- /desing-pattern/gobase/README.md: -------------------------------------------------------------------------------- 1 | 《Go语言底层原理剖析》中的部分示例 2 | 3 | [相关笔记文档](https://github.com/lixd/daily-notes/tree/master/Golang/read/Go%E8%AF%AD%E8%A8%80%E5%BA%95%E5%B1%82%E5%AE%9E%E7%8E%B0%E5%89%96%E6%9E%90) 4 | -------------------------------------------------------------------------------- /desing-pattern/gobase/ast/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type CollectRequest struct { 4 | Star int `form:"star" validation:"gte=1,lte=5" doc:"formData"` 5 | } 6 | -------------------------------------------------------------------------------- /desing-pattern/gobase/compiler/closure/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | a := 1 7 | b := 2 8 | go func() { 9 | fmt.Println(a, b) 10 | }() 11 | a = 100 12 | } 13 | 14 | // 查看当前程序闭包变量捕获的情况:go tool compile -m=2 main.go|grep capturing 15 | 16 | func do() { 17 | a := 1 18 | func() { 19 | fmt.Println(a) 20 | a = 2 21 | }() 22 | } 23 | 24 | func do2() { 25 | a := 1 26 | func1(&a) 27 | } 28 | 29 | func func1(a *int) { 30 | fmt.Println(*a) 31 | *a = 2 32 | } 33 | -------------------------------------------------------------------------------- /desing-pattern/gobase/compiler/compiler_test.go: -------------------------------------------------------------------------------- 1 | package compiler 2 | 3 | import ( 4 | "fmt" 5 | "go/scanner" 6 | "go/token" 7 | "testing" 8 | ) 9 | 10 | // 词法解析:将源文件进行 token 化 11 | func TestScanner(t *testing.T) { 12 | // 模拟解析源文件符号化 13 | src := []byte("cos(x) + si*sin(x) // Euler") 14 | var s scanner.Scanner 15 | fset := token.NewFileSet() 16 | file := fset.AddFile("", fset.Base(), len(src)) 17 | s.Init(file, src, nil, scanner.ScanComments) 18 | for { 19 | pos, tok, lit := s.Scan() 20 | if tok == token.EOF { 21 | break 22 | } 23 | fmt.Printf("%s\t%s\t%q\n", fset.Position(pos), tok, lit) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /desing-pattern/gobase/compiler/escape/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var z *int 4 | 5 | func escape() { 6 | a := 1 7 | z = &a 8 | } 9 | func escape2() int { 10 | a := 1 11 | z = &a // 虽然有引用,但是没有逃逸 12 | return *z 13 | } 14 | 15 | var o *int 16 | 17 | func escape3() { 18 | l := new(int) 19 | *l = 42 20 | m := &l 21 | n := &m 22 | o = **n 23 | } 24 | 25 | // 逃逸分析:go tool compile -m=2 main.go 26 | -------------------------------------------------------------------------------- /desing-pattern/gobase/compiler/inline/inline.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func sample() string { 4 | str := "hello" + "world" 5 | return str 6 | } 7 | 8 | func fib(i int) int { 9 | if i < 2 { 10 | return i 11 | } 12 | return fib(i-1) + fib(i-2) 13 | } 14 | 15 | func main() { 16 | sample() 17 | fib(10) 18 | } 19 | 20 | // 查看当前函数是否可以内联,以及不可以内联的原因:go tool compile -m=2 main.go 21 | -------------------------------------------------------------------------------- /desing-pattern/gobase/compiler/inline/inline_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | //go:noinline 6 | func max(a, b int) int { 7 | if a > b { 8 | return a 9 | } 10 | return b 11 | } 12 | 13 | var result int 14 | 15 | func BenchmarkInline(b *testing.B) { 16 | var r int 17 | for i := 0; i < b.N; i++ { 18 | r = max(-1, i) 19 | } 20 | result = r 21 | } 22 | -------------------------------------------------------------------------------- /desing-pattern/gobase/compiler/ssa/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "debug/elf" 5 | "log" 6 | ) 7 | 8 | // var d uint8 9 | // 10 | // func main() { 11 | // var a uint8 = 1 12 | // a = 2 13 | // if true { 14 | // a = 3 15 | // } 16 | // d = a 17 | // } 18 | 19 | // 查看SSA初始及其后续优化阶段生成的代码片段:GOSSAFUNC=main GOOS=linux GOARCH=amd64 go tool compile main.go 20 | // func main() { 21 | // fmt.Println("123") 22 | // } 23 | 24 | // 查看 elf 文件信息 25 | func main() { 26 | f, err := elf.Open("main") 27 | if err != nil { 28 | return 29 | } 30 | for _, section := range f.Sections { 31 | log.Println(section) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /desing-pattern/gobase/floatingpoint/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | func main() { 9 | var number float32 = 0.085 10 | fmt.Printf("Starting Number: %f\n\n", number) 11 | bits := math.Float32bits(number) 12 | binary := fmt.Sprintf("%.32b", bits) 13 | fmt.Printf(binary) 14 | } 15 | -------------------------------------------------------------------------------- /desing-pattern/goroutine-channel/timeout.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | ch := make(chan struct{}) 11 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) 12 | defer cancel() 13 | go timeout(ctx, ch) 14 | time.Sleep(time.Second) 15 | ch <- struct{}{} 16 | // do other logic 17 | time.Sleep(time.Second * 2) 18 | } 19 | 20 | func timeout(ctx context.Context, ch <-chan struct{}) { 21 | for { 22 | select { 23 | case <-ctx.Done(): 24 | fmt.Println("timeout") 25 | return 26 | case v := <-ch: 27 | fmt.Println(v) 28 | return 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /doc/compose/elasticsearch/cerebro.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | # cerebro 是一个简单的 ES 监控工具 4 | cerebro: 5 | image: lmenezes/cerebro:0.9.2 6 | container_name: cerebro 7 | restart: always 8 | ports: 9 | - "9000:9000" 10 | command: 11 | - -Dhosts.0.host=http://elk-es1:9200 12 | 13 | networks: 14 | default: 15 | external: 16 | name: elk -------------------------------------------------------------------------------- /doc/compose/elasticsearch/kibana.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | kibana: 4 | image: kibana:7.8.0 5 | container_name: elk-kibana 6 | restart: always 7 | environment: 8 | - ELASTICSEARCH_HOSTS=http://elk-es1:9200 9 | - I18N_LOCALE=zh-CN 10 | ports: 11 | - 5601:5601 12 | 13 | networks: 14 | default: 15 | external: 16 | name: elk 17 | -------------------------------------------------------------------------------- /doc/compose/etcd-single.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | networks: 3 | myetcd_single: 4 | services: 5 | etcd: 6 | image: quay.io/coreos/etcd 7 | container_name: etcd_single 8 | command: etcd -name etcd1 -advertise-client-urls http://0.0.0.0:2379 -listen-client-urls http://0.0.0.0:2379 -listen-peer-urls http://0.0.0.0:2380 9 | ports: 10 | - 12379:2379 11 | - 12380:2380 12 | volumes: 13 | - ./data:/etcd-data 14 | networks: 15 | - myetcd_single 16 | etcdkeeper: 17 | image: deltaprojects/etcdkeeper 18 | container_name: etcdkeeper_single 19 | ports: 20 | - 8088:8080 21 | networks: 22 | - myetcd_single -------------------------------------------------------------------------------- /doc/compose/mongodb.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | mongo-db: 4 | image: mongo 5 | restart: always 6 | # 自定义配置文件 7 | command: --config /etc/mongo/mongod.conf 8 | ports: 9 | - "27017:27017" 10 | environment: 11 | MONGO_INITDB_ROOT_USERNAME: root 12 | MONGO_INITDB_ROOT_PASSWORD: 123456 13 | volumes: 14 | # 日志 需要在宿主机修改为 777 权限容器里才能写入 15 | - ./log:/var/log/mongodb 16 | # 存储文件 17 | - ./db:/data/db 18 | # 配置文件 19 | - ./conf:/etc/mongo -------------------------------------------------------------------------------- /doc/compose/mysql.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | services: 3 | db: 4 | image: mysql:8 5 | restart: always 6 | environment: 7 | # 指定 root 账号的密码,即账号为root,密码为123456 8 | MYSQL_ROOT_PASSWORD: 123456 9 | command: 10 | --default-authentication-plugin=mysql_native_password 11 | --character-set-server=utf8mb4 12 | --collation-server=utf8mb4_general_ci 13 | --explicit_defaults_for_timestamp=true 14 | --lower_case_table_names=1 15 | ports: 16 | - 3306:3306 17 | volumes: 18 | - ./data:/var/lib/mysql -------------------------------------------------------------------------------- /doc/compose/postgressql.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | postgres: 4 | image: postgres:latest 5 | container_name: pgsql 6 | restart: always 7 | privileged: true 8 | ports: 9 | - 5432:5432 10 | environment: 11 | POSTGRES_USER: postgres 12 | POSTGRES_DB: postgres 13 | POSTGRES_PASSWORD: 123456 14 | PGDATA: /var/lib/postgresql/data/pgdata 15 | volumes: 16 | - ./data:/var/lib/postgresql/data/pgdata -------------------------------------------------------------------------------- /doc/compose/rabbitmq.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | rabbitmq: 4 | hostname: myrabbitmq 5 | image: rabbitmq:management 6 | ports: 7 | - 15672:15672 8 | - 5672:5672 9 | restart: always 10 | volumes: 11 | - ./data:/var/lib/rabbitmq -------------------------------------------------------------------------------- /doc/compose/redis.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | redis: 4 | hostname: redis 5 | image: redis 6 | container_name: redis 7 | restart: unless-stopped 8 | command: redis-server /etc/redis.conf 9 | environment: 10 | - TZ=Asia/Shanghai 11 | - LANG=en_US.UTF-8 12 | volumes: 13 | - /etc/localtime:/etc/localtime:ro 14 | - ./data:/data 15 | - ./conf/redis.conf:/etc/redis/redis.conf 16 | ports: 17 | - "6379:6379" -------------------------------------------------------------------------------- /etcd/lock/etcdlock_test.go: -------------------------------------------------------------------------------- 1 | package lock 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | /* 9 | 协程:2 抢锁成功 10 | 协程:2 释放锁 11 | 协程:1 抢锁成功 12 | 协程:1 释放锁 13 | 协程:0 抢锁成功 14 | 协程:0 释放锁 15 | 正常 16 | */ 17 | func TestEtcdMutex_Lock(t *testing.T) { 18 | var wg sync.WaitGroup 19 | for i := 0; i < 3; i++ { 20 | wg.Add(1) 21 | go testLock(10, "/mylock", i, &wg) 22 | } 23 | wg.Wait() 24 | } 25 | -------------------------------------------------------------------------------- /etcd/lock/mylock_test.go: -------------------------------------------------------------------------------- 1 | package lock 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | /* 9 | 协程 1 抢锁成功 10 | 协程 1 释放锁 11 | 协程 0 抢锁成功 12 | 协程 0 释放锁 13 | 协程 2 抢锁成功 14 | 协程 2 释放锁 15 | 16 | 正常 17 | */ 18 | func TestMyEtcdMutex_Lock(t *testing.T) { 19 | var waitGroup = new(sync.WaitGroup) 20 | for i := 0; i < 3; i++ { 21 | waitGroup.Add(1) 22 | go testLockSync(10, "/mylock", i, waitGroup) 23 | } 24 | waitGroup.Wait() 25 | } 26 | -------------------------------------------------------------------------------- /gin/graceful-restart/doc.go: -------------------------------------------------------------------------------- 1 | package graceful_restart 2 | 3 | // 相关笔记-Web服务优雅重启-https://github.com/lixd/daily-notes/blob/master/Golang/%E8%BF%9B%E9%98%B6/web%E6%9C%8D%E5%8A%A1%E4%BC%98%E9%9B%85%E5%85%B3%E6%9C%BA%E5%92%8C%E9%87%8D%E5%90%AF.md 4 | -------------------------------------------------------------------------------- /gin/helloworld/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | func main() { 6 | r := gin.Default() 7 | r.GET("/ping", func(c *gin.Context) { 8 | c.JSON(200, gin.H{ 9 | "message": "pong", 10 | }) 11 | }) 12 | r.Run() // listen and serve on 0.0.0.0:8080 13 | } 14 | -------------------------------------------------------------------------------- /gin/middleware/auth.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gin-gonic/gin" 7 | ) 8 | 9 | func AuthMiddleWare() gin.HandlerFunc { 10 | return func(c *gin.Context) { 11 | auth := c.DefaultQuery("auth", "false") 12 | if auth != "true" { 13 | c.JSON(http.StatusForbidden, gin.H{"status": "403", "message": "auth false"}) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /gin/middleware/redirect.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/gin-gonic/gin" 7 | "github.com/unrolled/secure" 8 | ) 9 | 10 | // HTTP2HTTPS Redirecting HTTP to HTTPS 11 | func HTTP2HTTPS() gin.HandlerFunc { 12 | return func(c *gin.Context) { 13 | middleware := secure.New(secure.Options{ 14 | SSLRedirect: true, 15 | SSLHost: "localhost:443", // https server 16 | }) 17 | err := middleware.Process(c.Writer, c.Request) 18 | if err != nil { 19 | // 如果出现错误,请不要继续 20 | fmt.Println(err) 21 | return 22 | } 23 | // 继续往下处理 24 | c.Next() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /gin/simple/router.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | // 1.存到路由表中 map结构 pattern为key value就是func 10 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 11 | w.Write([]byte("Hello World")) 12 | }) 13 | // 内部调用net.Listen("tcp", addr)初始化socket, bind, listen的操作. 14 | // 同时根据请求的host+url匹配路由表中的func 没有则返回 NotFoundHandler 404 15 | if err := http.ListenAndServe(":8000", nil); err != nil { 16 | fmt.Println("start http server fail:", err) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /gin/swagger/Makefile: -------------------------------------------------------------------------------- 1 | # 初始化 swagger 2 | .PHONY:api-swag 3 | swag: 4 | @echo 开始初始化 swagger 文档 5 | swag init -g main.go -o docs 6 | @echo 开始格式化 swagger 注释 7 | swag fmt -g main.go 8 | 9 | # dev,带docs,二进制文件会比较大 10 | .PHONY:dev 11 | dev: 12 | go build -tags "doc" 13 | 14 | # prod,不带docs,二进制文件会小一些,而且生产环境也不应该把docs暴露出去 15 | .PHONY:prod 16 | prod: 17 | go build 18 | -------------------------------------------------------------------------------- /gin/swagger/doc.go: -------------------------------------------------------------------------------- 1 | //go:build doc 2 | 3 | package main 4 | 5 | import ( 6 | _ "i-go/gin/swagger/docs" 7 | 8 | ginSwagger "github.com/swaggo/gin-swagger" 9 | ) 10 | 11 | func init() { 12 | swagHandler = ginSwagger.WrapHandler(files.Handler) 13 | } 14 | -------------------------------------------------------------------------------- /gin/swagger/swagger-auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lixd/i-go/d2d1491693f31efa867c5132765bbe4e693f25dc/gin/swagger/swagger-auth.png -------------------------------------------------------------------------------- /gin/templates/index.tmpl: -------------------------------------------------------------------------------- 1 | 2 |

3 | {{ .title }} 4 |

5 | -------------------------------------------------------------------------------- /gin/user/userModel.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | type User struct { 4 | Name string `json:"name" form:"name"` 5 | Age int `json:"age" form:"age"` 6 | Address string `json:"address" form:"address"` 7 | } 8 | type LoginForm struct { 9 | User string `json:"user" form:"user"` 10 | Password string `json:"password" form:"password"` 11 | } 12 | type Class struct { 13 | Id string `json:"id" form:"id"` 14 | Number int `json:"number" form:"number"` 15 | } 16 | -------------------------------------------------------------------------------- /gin/validator/example/register.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/gin-gonic/gin/binding" 7 | "github.com/go-playground/validator/v10" 8 | ) 9 | 10 | // 自定义错误提示信息的字段名 11 | func Register() { 12 | if v, ok := binding.Validator.Engine().(*validator.Validate); ok { 13 | v.RegisterTagNameFunc(JsonTag) 14 | v.RegisterStructValidation(SignUpParamStructLevelValidation, &SignUpParam{}) 15 | if err := v.RegisterValidation("checkDate", customFunc); err != nil { 16 | fmt.Println(err) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gin/validator/validate.http: -------------------------------------------------------------------------------- 1 | POST http://localhost:8999/signup 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "", 6 | "age": 24, 7 | "email": "17x@gmail.com", 8 | "password": "123456", 9 | "rePassword": "1234567", 10 | "date": "" 11 | } 12 | 13 | ### -------------------------------------------------------------------------------- /go-kit/hello/client/cmd/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "i-go/go-kit/hello/client/services" 7 | "net/url" 8 | "os" 9 | 10 | httpTransport "github.com/go-kit/kit/transport/http" 11 | ) 12 | 13 | func main() { 14 | target, _ := url.Parse("http://localhost:8080") 15 | client := httpTransport.NewClient("GET", target, services.GetUserInfoReq, services.GetUserInfoResp) 16 | endpoint := client.Endpoint() 17 | i, err := endpoint(context.Background(), services.UserRequest{UserId: 999}) 18 | if err != nil { 19 | fmt.Println(err) 20 | os.Exit(1) 21 | } 22 | // response := i.(services.UserResponse) 23 | fmt.Println(i) 24 | } 25 | -------------------------------------------------------------------------------- /go-kit/hello/client/services/user_endpoint.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | type UserRequest struct { 4 | UserId int `json:"userId"` 5 | } 6 | type UserResponse struct { 7 | Username string `json:"username"` 8 | } 9 | -------------------------------------------------------------------------------- /go-kit/hello/server/cmd/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | 6 | "i-go/go-kit/hello/server/services" 7 | 8 | httpTransport "github.com/go-kit/kit/transport/http" 9 | ) 10 | 11 | func main() { 12 | user := services.UserServer{} 13 | endpoint := services.GenUserEndpoint(&user) 14 | server := httpTransport.NewServer(endpoint, services.DecodeUserRequest, services.EncodeUserResponse) 15 | if err := http.ListenAndServe(":8080", server); err != nil { 16 | panic(err) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /go-kit/hello/server/services/user_endpoint.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/go-kit/kit/endpoint" 7 | ) 8 | 9 | type UserRequest struct { 10 | UserId int `json:"userId"` 11 | } 12 | type UserResponse struct { 13 | Username string `json:"username"` 14 | } 15 | 16 | func GenUserEndpoint(service IUser) endpoint.Endpoint { 17 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 18 | r := request.(UserRequest) 19 | name := service.GetName(r.UserId) 20 | return UserResponse{Username: name}, nil 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /go-kit/hello/server/services/user_service.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | type IUser interface { 4 | GetName(userId int) string 5 | } 6 | 7 | type UserServer struct { 8 | } 9 | 10 | func (us *UserServer) GetName(userId int) string { 11 | if userId == 999 { 12 | return "admin" 13 | } 14 | return "guest" 15 | } 16 | -------------------------------------------------------------------------------- /go-kit/official/stringsvc1/README.md: -------------------------------------------------------------------------------- 1 | stringsvc1 一个简单的,基于 Go kit 的服务。 2 | 3 | 所有代码都挤在 main.go 中 4 | 5 | 定义了 server、transport、endpoint 等组件。 -------------------------------------------------------------------------------- /go-kit/official/stringsvc1/stringsvc1.http: -------------------------------------------------------------------------------- 1 | ### uppercase 2 | GET http://localhost:8080/uppercase 3 | Content-Type: application/json 4 | 5 | { 6 | "s": "hello, 17x" 7 | } 8 | 9 | ### count 10 | GET http://localhost:8080/count 11 | Content-Type: application/json 12 | 13 | { 14 | "s": "hello, 17x" 15 | } 16 | 17 | ### -------------------------------------------------------------------------------- /go-kit/official/stringsvc2/README.md: -------------------------------------------------------------------------------- 1 | stringsvc2 在 stringsvc1 的基础上 新增了 logging、instrumentation 2 | 这两个 middleware 3 | 4 | 同时将代码分散到了不同的文件中,使得整体结构更加清晰。 -------------------------------------------------------------------------------- /go-kit/official/stringsvc2/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | // logic and req resp structure 9 | type StringService interface { 10 | Uppercase(string) (string, error) 11 | Count(string) int 12 | } 13 | 14 | type stringService struct{} 15 | 16 | func (stringService) Uppercase(s string) (string, error) { 17 | if s == "" { 18 | return "", ErrEmpty 19 | } 20 | return strings.ToUpper(s), nil 21 | } 22 | 23 | func (stringService) Count(s string) int { 24 | return len(s) 25 | } 26 | 27 | // ErrEmpty is returned when input string is empty 28 | var ErrEmpty = errors.New("Empty string") 29 | -------------------------------------------------------------------------------- /go-kit/official/stringsvc2/stringsvc2.http: -------------------------------------------------------------------------------- 1 | ### uppercase 2 | GET http://localhost:8080/uppercase 3 | Content-Type: application/json 4 | 5 | { 6 | "s": "admin" 7 | } 8 | 9 | ### count 10 | GET http://localhost:8080/count 11 | Content-Type: application/json 12 | 13 | { 14 | "s": "hello, 17x" 15 | } 16 | 17 | ### metrics 18 | GET http://localhost:8080/metrics 19 | Content-Type: application/json 20 | 21 | { 22 | "s": "hello, 17x" 23 | } 24 | 25 | ### -------------------------------------------------------------------------------- /go-kit/official/stringsvc3/README.md: -------------------------------------------------------------------------------- 1 | stringsvc2 在 stringsvc1 的基础上 新增了 logging、instrumentation 2 | 这两个 middleware 3 | 4 | 同时将代码分散到了不同的文件中,使得整体结构更加清晰。 -------------------------------------------------------------------------------- /go-kit/official/stringsvc3/stringsvc3.http: -------------------------------------------------------------------------------- 1 | ### uppercase 2 | GET http://localhost:8080/uppercase 3 | Content-Type: application/json 4 | 5 | { 6 | "s": "admin" 7 | } 8 | 9 | ### count 10 | GET http://localhost:8080/count 11 | Content-Type: application/json 12 | 13 | { 14 | "s": "hello, 17x" 15 | } 16 | 17 | ### metrics 18 | GET http://localhost:8080/metrics 19 | Content-Type: application/json 20 | 21 | { 22 | "s": "hello, 17x" 23 | } 24 | 25 | ### -------------------------------------------------------------------------------- /gomock/db/db.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | type DB interface { 4 | Get(key string) (int, error) 5 | } 6 | 7 | // mockgen 生成 mock 文件 一般传递三个参数。包含需要被mock的接口得到源文件source,生成的目标文件destination,包名package 8 | 9 | //go:generate mockgen -source=db.go -destination=./db_mock.go -package=db 10 | func GetFromDB(db DB, key string) int { 11 | if value, err := db.Get(key); err == nil { 12 | return value 13 | } 14 | 15 | return -1 16 | } 17 | -------------------------------------------------------------------------------- /gomock/db/db_test.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | ) 9 | 10 | func TestGetFromDB(t *testing.T) { 11 | ctrl := gomock.NewController(t) 12 | defer ctrl.Finish() // 断言 DB.Get() 方法是否被调用 13 | 14 | m := NewMockDB(ctrl) 15 | m.EXPECT().Get(gomock.Eq("Tom")).Return(100, errors.New("not exist")) 16 | 17 | if v := GetFromDB(m, "Tom"); v != -1 { 18 | t.Fatal("expected -1, but got", v) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /hack/update-goimports.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | KUBE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" 8 | cd "${KUBE_ROOT}/hack" || exit 1 9 | 10 | if ! command -v goimports &> /dev/null 11 | then 12 | echo "goimports could not be found on your machine, please install it first" 13 | exit 14 | fi 15 | 16 | cd "${KUBE_ROOT}" || exit 1 17 | 18 | IFS=$'\n' read -r -d '' -a files < <( find . -type f -name '*.go' ! -name 'mock_*.go' ! -name '*.pb.go' && printf '\0' ) 19 | 20 | "goimports" -w -local github.com/kubeclipper/kubeclipper "${files[@]}" 21 | -------------------------------------------------------------------------------- /ient/ent/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package predicate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | ) 8 | 9 | // User is the predicate function for user builders. 10 | type User func(*sql.Selector) 11 | -------------------------------------------------------------------------------- /ient/ent/runtime/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package runtime 4 | 5 | // The schema-stitching logic is generated in i-go/ient/ent/runtime.go 6 | 7 | const ( 8 | Version = "v0.12.3" // Version of ent codegen. 9 | Sum = "h1:N5lO2EOrHpCH5HYfiMOCHYbo+oh5M8GjT0/cx5x6xkk=" // Sum of ent codegen. 10 | ) 11 | -------------------------------------------------------------------------------- /ient/ent/schema/property/user.go: -------------------------------------------------------------------------------- 1 | package property 2 | 3 | type UserType string 4 | 5 | const ( 6 | UserTypeSystem UserType = "system" 7 | UserTypeUser UserType = "register" 8 | ) 9 | 10 | func (r UserType) String() string { 11 | return string(r) 12 | } 13 | 14 | // Values CredentialType list valid values for Enum. 15 | func (UserType) Values() (kinds []string) { 16 | for _, s := range []UserType{UserTypeSystem, UserTypeUser} { 17 | kinds = append(kinds, string(s)) 18 | } 19 | return 20 | } 21 | -------------------------------------------------------------------------------- /ient/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "i-go/17x/ient/ent" 6 | "log" 7 | 8 | _ "github.com/go-sql-driver/mysql" 9 | ) 10 | 11 | func main() { 12 | client, err := ent.Open("mysql", "root:your-sql-password@tcp(172.20.150.246:3306)/test?parseTime=true") 13 | if err != nil { 14 | log.Fatalf("failed opening connection to mysql: %v", err) 15 | } 16 | defer client.Close() 17 | // Run the auto migration tool. 18 | if err := client.Schema.Create(context.Background()); err != nil { 19 | log.Fatalf("failed creating schema resources: %v", err) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /image/assets/origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lixd/i-go/d2d1491693f31efa867c5132765bbe4e693f25dc/image/assets/origin.png -------------------------------------------------------------------------------- /image/core/key.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | const ( 4 | originImage = "../assets/origin.png" 5 | ) 6 | -------------------------------------------------------------------------------- /image/core/quality.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "bytes" 5 | "image" 6 | "image/jpeg" 7 | 8 | "github.com/pkg/errors" 9 | ) 10 | 11 | // Quality 图片质量调整 12 | func Quality(origin image.Image, q int) (image.Image, error) { 13 | var buf bytes.Buffer 14 | err := jpeg.Encode(&buf, origin, &jpeg.Options{Quality: q}) 15 | if err != nil { 16 | return nil, errors.Wrap(err, "encode") 17 | } 18 | reader := bytes.NewReader(buf.Bytes()) 19 | decode, _, err := image.Decode(reader) 20 | if err != nil { 21 | return nil, errors.Wrap(err, "decode") 22 | } 23 | return decode, nil 24 | } 25 | -------------------------------------------------------------------------------- /image/util/conv.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "bytes" 5 | "image" 6 | "image/jpeg" 7 | ) 8 | 9 | // Bytes2Image 转换耗时和图片尺寸有关 10 | func Bytes2Image(origin []byte) (image.Image, error) { 11 | reader := bytes.NewReader(origin) 12 | return jpeg.Decode(reader) 13 | } 14 | 15 | // Image2Bytes 图片转 byte 数组 16 | func Image2Bytes(img image.Image) ([]byte, error) { 17 | buf := bytes.Buffer{} 18 | err := jpeg.Encode(&buf, img, &jpeg.Options{Quality: 100}) 19 | return buf.Bytes(), err 20 | } 21 | -------------------------------------------------------------------------------- /kratos/Makefile: -------------------------------------------------------------------------------- 1 | gen-gw: 2 | protoc --proto_path=./google \ 3 | --go_out=/proto --go_opt=paths=source_relative \ 4 | --go-grpc_out=. --go-grpc_opt=paths=source_relative \ 5 | --grpc-gateway_out=. --grpc-gateway_opt=paths=source_relative \ 6 | .hello_world.proto 7 | -------------------------------------------------------------------------------- /log/logrus/cutfile/logrus.go: -------------------------------------------------------------------------------- 1 | package cutfile 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/sirupsen/logrus" 7 | ) 8 | 9 | const ( 10 | // LogPath 日志存储位置 11 | LogPath = "./log/zap/logs" 12 | // MaxAge 日志文件最大保存时间 13 | MaxAge = time.Hour * 24 * 90 14 | ) 15 | 16 | func main() { 17 | hook := NewLfsHook(LogPath, MaxAge) 18 | // 添加hook 19 | logrus.AddHook(hook) 20 | // 会打印出DefaultFieldHook中添加的field appName=MyAppName 21 | logrus.Info("") // time="2020-03-13T18:42:08+08:00" level=info appName=MyAppName 22 | } 23 | -------------------------------------------------------------------------------- /log/logrus/hook/logrus.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/sirupsen/logrus" 4 | 5 | func main() { 6 | // 添加hook 7 | logrus.AddHook(new(DefaultFieldHook)) 8 | // 会打印出DefaultFieldHook中添加的field appName=MyAppName 9 | logrus.Info("") // time="2020-03-13T18:42:08+08:00" level=info appName=MyAppName 10 | } 11 | -------------------------------------------------------------------------------- /log/logrus/hook/simplehook.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/sirupsen/logrus" 4 | 5 | // DefaultFieldHook 需要实现Fire和Levels接口 6 | type DefaultFieldHook struct { 7 | } 8 | 9 | // Fire 修改 logrus.Entry 具体的hook代码 10 | func (hook *DefaultFieldHook) Fire(entry *logrus.Entry) error { 11 | entry.Data["appName"] = "MyAppName" 12 | return nil 13 | } 14 | 15 | // Levels 这里返回触发Fire方法的日志等级 16 | func (hook *DefaultFieldHook) Levels() []logrus.Level { 17 | return logrus.AllLevels 18 | } 19 | -------------------------------------------------------------------------------- /log/logrus/simple/logrus.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | ) 6 | 7 | func main() { 8 | log.WithFields(log.Fields{ 9 | "animal": "walrus", 10 | }).Info("A walrus appears") 11 | } 12 | -------------------------------------------------------------------------------- /mq/kafka/FAQ/assets/kafka-client-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lixd/i-go/d2d1491693f31efa867c5132765bbe4e693f25dc/mq/kafka/FAQ/assets/kafka-client-arch.png -------------------------------------------------------------------------------- /mq/kafka/FAQ/blog.md: -------------------------------------------------------------------------------- 1 | [从面试角度一文学完 Kafka](https://mp.weixin.qq.com/s?__biz=MzkzMDI1NjcyOQ==&mid=2247487730&idx=1&sn=c51de28679d92f9086f1b94e72a5cb62&source=41#wechat_redirect) 2 | -------------------------------------------------------------------------------- /mq/kafka/demo/benchmark/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strconv" 5 | 6 | "i-go/mq/kafka" 7 | "i-go/mq/kafka/demo/consumer/group" 8 | "i-go/mq/kafka/demo/producer/async" 9 | ) 10 | 11 | func main() { 12 | topic := kafka.Topic3 13 | limit := 100000 14 | for i := 0; i < 20; i++ { 15 | go group.ConsumerGroup(topic, "cg2", "CG"+strconv.Itoa(i)) 16 | } 17 | for i := 0; i < 100; i++ { 18 | go async.Producer(topic, limit) 19 | } 20 | select {} 21 | } 22 | -------------------------------------------------------------------------------- /mq/kafka/demo/consumer/standalone/cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "i-go/mq/kafka" 7 | "i-go/mq/kafka/demo/consumer/standalone" 8 | "i-go/mq/kafka/demo/producer/sync" 9 | ) 10 | 11 | // 测试 独立消费者 先启动消费者再启动生产者 12 | func main() { 13 | topic := kafka.Topic 14 | go standalone.SinglePartition(topic) 15 | // go standalone.Partitions(topic) 16 | time.Sleep(time.Millisecond * 100) 17 | sync.Producer(topic, 100) 18 | time.Sleep(time.Second * 10) 19 | } 20 | -------------------------------------------------------------------------------- /mq/kafka/demo/offsetmanager/cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "i-go/mq/kafka" 7 | "i-go/mq/kafka/demo/offsetmanager" 8 | "i-go/mq/kafka/demo/producer/async" 9 | ) 10 | 11 | func main() { 12 | topic := kafka.Topic 13 | go offsetmanager.OffsetManager(topic) 14 | time.Sleep(time.Second) // sleep 让 consumer 先启动 15 | async.Producer(topic, 100) 16 | time.Sleep(time.Second * 10) 17 | } 18 | -------------------------------------------------------------------------------- /mq/kafka/demo/producer/async/cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "i-go/mq/kafka" 7 | "i-go/mq/kafka/demo/consumer/standalone" 8 | "i-go/mq/kafka/demo/producer/async" 9 | ) 10 | 11 | func main() { 12 | topic := kafka.Topic 13 | go standalone.SinglePartition(topic) 14 | time.Sleep(time.Millisecond * 100) // 延迟,让consumer启动后再启动生产者 15 | async.Producer(topic, 100) 16 | 17 | time.Sleep(time.Second * 10) 18 | } 19 | -------------------------------------------------------------------------------- /mq/kafka/demo/producer/sync/cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "i-go/mq/kafka" 7 | "i-go/mq/kafka/demo/consumer/standalone" 8 | "i-go/mq/kafka/demo/producer/sync" 9 | ) 10 | 11 | func main() { 12 | topic := kafka.Topic 13 | // 先启动消费者,保证能消费到后续发送的消息 14 | go standalone.SinglePartition(topic) 15 | time.Sleep(time.Second) 16 | sync.Producer(topic, 100) 17 | // sleep 等待消费结束 18 | time.Sleep(time.Second * 10) 19 | } 20 | -------------------------------------------------------------------------------- /mq/kafka/lesson/compression/cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "i-go/mq/kafka" 7 | "i-go/mq/kafka/demo/consumer/standalone" 8 | "i-go/mq/kafka/lesson/compression" 9 | ) 10 | 11 | func main() { 12 | topic := kafka.TopicCompression 13 | // 先启动消费者,保证能消费到后续发送的消息 14 | go standalone.SinglePartition(topic) 15 | time.Sleep(time.Second) 16 | compression.Producer(topic, 1000) 17 | // sleep 等待消费结束 18 | time.Sleep(time.Second * 10) 19 | } 20 | -------------------------------------------------------------------------------- /mq/kafka/lesson/exactlyonce/cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "i-go/mq/kafka" 7 | "i-go/mq/kafka/demo/consumer/standalone" 8 | "i-go/mq/kafka/lesson/exactlyonce" 9 | ) 10 | 11 | func main() { 12 | topic := kafka.Topic 13 | // 先启动消费者,保证能消费到后续发送的消息 14 | go standalone.SinglePartition(topic) 15 | time.Sleep(time.Second) 16 | exactlyonce.Producer(topic, 10) 17 | // sleep 等待消费结束 18 | time.Sleep(time.Second * 10) 19 | } 20 | -------------------------------------------------------------------------------- /mq/kafka/lesson/partition/cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "i-go/mq/kafka" 7 | "i-go/mq/kafka/demo/consumer/standalone" 8 | "i-go/mq/kafka/lesson/partition" 9 | ) 10 | 11 | func main() { 12 | topic := kafka.TopicPartition 13 | // 先启动消费者,保证能消费到后续发送的消息 14 | go standalone.SinglePartition(topic) 15 | time.Sleep(time.Second) 16 | partition.Producer(topic, 100) 17 | // sleep 等待消费结束 18 | time.Sleep(time.Second * 10) 19 | } 20 | -------------------------------------------------------------------------------- /mq/nats/constant/constant.go: -------------------------------------------------------------------------------- 1 | package constant 2 | 3 | import "time" 4 | 5 | // pub/sub 6 | const ( 7 | ClusterID = "ND4N3DCKP5XUKBIB7O4MTEB2JURIVSSHV55Z6OQICJR4ZJQHQO22EL7K" 8 | DurableId = "durable-test" 9 | MaxInflight = 1000 10 | AckWait = time.Second * 3 11 | DefaultNatsURL = "nats://172.20.150.199:4222" 12 | DefaultSubject = "defaultSubject" 13 | DefaultQueue = "defaultQueue" 14 | DefaultId = "client_testId" 15 | ) 16 | -------------------------------------------------------------------------------- /mq/nats/nats/README.md: -------------------------------------------------------------------------------- 1 | NATS只有基础功能 2 | 没有持久化等功能 3 | 4 | 安装 5 | ```shell script 6 | docker pull nats:latest 7 | docker run -p 4222:4222 -ti nats:latest 8 | ``` -------------------------------------------------------------------------------- /mq/nats/nats/msghandler/print.go: -------------------------------------------------------------------------------- 1 | package msghandler 2 | 3 | import ( 4 | "github.com/nats-io/nats.go" 5 | "github.com/sirupsen/logrus" 6 | ) 7 | 8 | // Simple 简单的消息处理方法 可以看成消费者 9 | func Simple(msg *nats.Msg) { 10 | logrus.Println(string(msg.Data)) 11 | } 12 | -------------------------------------------------------------------------------- /mq/nats/nats/nats-pub/pub_test.go: -------------------------------------------------------------------------------- 1 | package nats_pub 2 | 3 | import ( 4 | "testing" 5 | 6 | "i-go/mq/nats/constant" 7 | ) 8 | 9 | func TestPublishMsg(t *testing.T) { 10 | for i := 0; i < 99; i++ { 11 | PublishMsg(constant.DefaultSubject, []byte("hello nats")) 12 | } 13 | Release() 14 | } 15 | -------------------------------------------------------------------------------- /mq/nats/nats/nats-sub/sub_test.go: -------------------------------------------------------------------------------- 1 | package nats_sub 2 | 3 | import ( 4 | "os" 5 | "os/signal" 6 | "syscall" 7 | "testing" 8 | 9 | "i-go/mq/nats/constant" 10 | "i-go/mq/nats/nats/msghandler" 11 | ) 12 | 13 | func TestSubscribe(t *testing.T) { 14 | Subscribe(constant.DefaultSubject, msghandler.Simple) 15 | s := make(chan os.Signal, 1) 16 | signal.Notify(s, syscall.SIGINT, syscall.SIGTERM) 17 | <-s 18 | UnSubscribe() 19 | } 20 | -------------------------------------------------------------------------------- /mq/nats/nats/request-reply/request.go: -------------------------------------------------------------------------------- 1 | package request_reply 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "i-go/mq/nats/nats/conn" 8 | 9 | "github.com/nats-io/nats.go" 10 | "github.com/sirupsen/logrus" 11 | ) 12 | 13 | var ( 14 | nc *nats.Conn 15 | err error 16 | ) 17 | 18 | func init() { 19 | nc, err = conn.NewConn() 20 | if err != nil { 21 | panic(err) 22 | } 23 | } 24 | 25 | func Request(subject string, msg []byte) { 26 | resp, err := nc.Request(subject, msg, time.Minute*10) 27 | if err != nil { 28 | logrus.WithField("scene", "nats publish").Error(err) 29 | return 30 | } 31 | fmt.Printf("request %v reply:%+v\n", string(msg), string(resp.Data)) 32 | } 33 | -------------------------------------------------------------------------------- /mq/nats/nats/request-reply/request_test.go: -------------------------------------------------------------------------------- 1 | package request_reply 2 | 3 | import ( 4 | "net" 5 | "strconv" 6 | "testing" 7 | ) 8 | 9 | func TestRequest(t *testing.T) { 10 | stopChan := make(chan struct{}) 11 | Subscribe("hello", demoHandler, stopChan) 12 | for i := 0; i < 10; i++ { 13 | Request("hello", []byte(strconv.Itoa(i))) 14 | } 15 | stopChan <- struct{}{} 16 | } 17 | 18 | func TestA(t *testing.T) { 19 | addresses, err := net.InterfaceAddrs() 20 | if err != nil { 21 | t.Fatal(err) 22 | } 23 | for _, address := range addresses { 24 | t.Log(address) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /mq/nats/stan/README.md: -------------------------------------------------------------------------------- 1 | STAN即NATS streaming 2 | NATS Streaming 服务器有持久化日志功能,而且它提供了很多从 NATS 服务器订阅消息的功能。 3 | 4 | 有几种类型的 NATS Streaming 订阅: 5 | 定期的 6 | 持久化的 7 | 队列组 (Queue Group) 8 | 重传 (Redelivery) 9 | 10 | ```sh 11 | 下载解压运行即可 12 | https://github.com/nats-io/nats-streaming-server/releases 13 | ``` -------------------------------------------------------------------------------- /mq/nats/stan/msghandler/print.go: -------------------------------------------------------------------------------- 1 | package msghandler 2 | 3 | import "github.com/sirupsen/logrus" 4 | 5 | // Simple 简单的消息处理方法 可以看成消费者 6 | func Simple(msg []byte) { 7 | logrus.Println(string(msg)) 8 | } 9 | -------------------------------------------------------------------------------- /mq/nats/stan/stan-pub/pub_test.go: -------------------------------------------------------------------------------- 1 | package stan_pub 2 | 3 | import ( 4 | "testing" 5 | 6 | "i-go/mq/nats/constant" 7 | ) 8 | 9 | func TestPublishMsg(t *testing.T) { 10 | for i := 0; i < 999; i++ { 11 | PublishMsg(constant.DefaultSubject, []byte("hello nats-streaming")) 12 | } 13 | Release() 14 | } 15 | -------------------------------------------------------------------------------- /mq/nats/stan/stan-sub/sub_test.go: -------------------------------------------------------------------------------- 1 | package stan_sub 2 | 3 | import ( 4 | "os" 5 | "os/signal" 6 | "syscall" 7 | "testing" 8 | "time" 9 | 10 | "i-go/mq/nats/constant" 11 | "i-go/mq/nats/stan/msghandler" 12 | ) 13 | 14 | func TestStartMany(t *testing.T) { 15 | StartMany(2, constant.DefaultSubject, constant.DefaultQueue, msghandler.Simple) 16 | s := make(chan os.Signal, 1) 17 | signal.Notify(s, syscall.SIGINT, syscall.SIGTERM) 18 | <-s 19 | Unsubscribe() 20 | time.Sleep(time.Second * 3) 21 | // 这里释放资源关闭连接什么的 22 | } 23 | -------------------------------------------------------------------------------- /other/cpucache/array.go: -------------------------------------------------------------------------------- 1 | package cpucache 2 | 3 | const ( 4 | row = 1024 5 | col = 512 6 | ) 7 | 8 | /* 9 | 逐行遍历可以用到 CPU 缓存,数组在内存中是以行为单位存储的,例如:row1,row2,row3 这样一行一行挨着的。 10 | CPU 每次从内存中取一行加载到CPU缓存(CPU Cache Line)中,如果按照行读取则可以用到CPU缓存,相比逐列遍历,效率自然更高 11 | */ 12 | var ( 13 | matrix = [row][col]int64{} 14 | sum int64 15 | ) 16 | 17 | // Row 逐行遍历 18 | func Row() { 19 | for i := 0; i < row; i++ { 20 | for j := 0; j < col; j++ { 21 | sum += matrix[i][j] 22 | } 23 | } 24 | } 25 | 26 | // Col 逐列遍历 27 | func Col() { 28 | for j := 0; j < col; j++ { 29 | for i := 0; i < row; i++ { 30 | sum += matrix[i][j] 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /other/cpucache/array_test.go: -------------------------------------------------------------------------------- 1 | package cpucache 2 | 3 | import "testing" 4 | 5 | // 748990 ns/op 6 | func BenchmarkFor1(b *testing.B) { 7 | for i := 0; i < b.N; i++ { 8 | Row() 9 | } 10 | } 11 | 12 | // 1382133 ns/op 13 | func BenchmarkFor2(b *testing.B) { 14 | for i := 0; i < b.N; i++ { 15 | Col() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /other/hash/hash_test.go: -------------------------------------------------------------------------------- 1 | package hash 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "testing" 7 | ) 8 | 9 | // 大致算是均匀分配 10 | func TestNew(t *testing.T) { 11 | var ( 12 | static = make(map[string]int) 13 | ) 14 | m := New(100, nil) 15 | physical := []string{"A", "B", "C", "D", "E"} 16 | m.Add(physical...) 17 | for i := 0; i < 500_0000; i++ { 18 | key := strconv.Itoa(i) 19 | get := m.Get(key) 20 | static[get] += 1 21 | } 22 | fmt.Println(static) 23 | } 24 | -------------------------------------------------------------------------------- /shell/comom.sh: -------------------------------------------------------------------------------- 1 | # 统计进程打开的FD 2 | lsof -n| awk '{print $3}'|sort|uniq -c|sort -nr|head -10 3 | # 统计用户打开的FD 4 | lsof -n| awk '{print $2}'|sort|uniq -c|sort -nr|head -10 5 | # 统计命令打开的FD 6 | lsof -n| awk '{print $1}'|sort|uniq -c|sort -nr|head -10 7 | 8 | # aliyun cdn log analyzer 被访问次数最多的url及访问用户ip 9 | awk '{print $3$8}' {filename} |\ 10 | awk '{ips[$1]++;next} END {for (ip in ips) print ips[ip] " " ip}'|\ 11 | sort -rn|\ 12 | head -n 10 13 | 14 | 15 | # 查看TCP连接数及其状态 16 | netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 17 | 18 | # 查看句柄占用情况 模糊值 19 | lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|more 20 | 21 | # 查看句柄占用情况 精确值 22 | ls /proc/$pid/fd/ |wc -l 23 | 24 | -------------------------------------------------------------------------------- /shell/doc.go: -------------------------------------------------------------------------------- 1 | package shell 2 | 3 | // 日常收集的一些shell脚本 4 | -------------------------------------------------------------------------------- /shell/docker-clear.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 移除已经停止的容器 3 | docker system prune -f 4 | # 删除当前没有使用(即没有启动为container的)的镜像 5 | docker image prune -a 6 | -------------------------------------------------------------------------------- /shell/docker.sh: -------------------------------------------------------------------------------- 1 | # 使用 dive 分析镜像 2 | docker run --rm -it \ 3 | -v /var/run/docker.sock:/var/run/docker.sock \ 4 | -e DOCKER_API_VERSION=1.37 \ 5 | wagoodman/dive:latest {ImageID} 6 | -------------------------------------------------------------------------------- /shell/install-chisel.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | wget https://github.com/jpillora/chisel/releases/download/v1.7.7/chisel_1.7.7_linux_amd64.gz 5 | gzip -d chisel_1.7.7_linux_amd64.gz 6 | chmod +x chisel_1.7.7_linux_amd64 7 | mv chisel_1.7.7_linux_amd64 /usr/local/bin/chisel 8 | -------------------------------------------------------------------------------- /shell/install-docker-compose.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | # centos一键安装docker-compose脚本. 4 | # usage: sh install-docker-compose.sh 5 | # 第一步 下载二进制文件到/usr/local/bin/位置 6 | curl -L https://github.com/docker/compose/releases/download/1.24.0/docker-compose-"$(uname -s)"-"$(uname -m)" -o /usr/local/bin/docker-compose 7 | # 第二步 赋予可执行权限 8 | chmod +x /usr/local/bin/docker-compose 9 | 10 | #查看版本号 11 | docker-compose version 12 | -------------------------------------------------------------------------------- /shell/install-nfs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # centos一键安装nfs 5 | # 如何使用 sh install-nfs.sh 6 | # nfs 挂载测试:mount -t nfs 127.0.0.1(服务器地址):/tmp/nfs/data(nfs的共享目录) /opt/kc/backups(挂载目标目录) 7 | # 安装nfs 8 | yum install -y nfs-utils rpcbind 9 | # 检测 nfs 服务是否安装成功 10 | rpcinfo -p localhost 11 | # 写入配置文件,当前默认共享 /tmp/nfs/data 目录 12 | mkdir -p /tmp/nfs/data 13 | echo '/tmp/nfs/data *(rw,sync,no_root_squash,no_subtree_check,fsid=0)' > /etc/exports 14 | # 先启动 rpcbind 再启动 nfs 15 | systemctl enable rpcbind --now 16 | systemctl enable nfs --now 17 | # 使 nfs 最新配置生效 18 | exportfs -r 19 | exportfs -v 20 | # 查看共享路径 21 | showmount -e 127.0.0.1 22 | echo 'nfs install finish.' 23 | -------------------------------------------------------------------------------- /shell/install-nodejs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 使用 NVM 安装 NodeJS 多个版本并进行管理 3 | # 使用方式:source install-nodejs.sh 4 | # 安装Git 5 | set -e 6 | yum install git -y 7 | #使用Git将NVM的源码克隆到本地的~/.nvm目录下,并检查最新版本。 8 | git clone https://github.com/cnpm/nvm.git ~/.nvm 9 | cd ~/.nvm 10 | git checkout `git describe --abbrev=0 --tags` 11 | #配置NVM环境变量 12 | echo ". ~/.nvm/nvm.sh" >> /etc/profile 13 | source /etc/profile 14 | #查看 nodejs 版本 15 | nvm list-remote 16 | #安装 v16.13.0 17 | nvm install v16.13.0 18 | 19 | #可以安装多个版本,使用 nvm ls 查看,使用 nvm use <版本号> 切换 20 | -------------------------------------------------------------------------------- /shell/install-openssl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # centos一键安装openssl 1.1.1 版本 5 | # 下载相关依赖 6 | yum update -y 7 | yum install -y wget tar make gcc perl pcre-devel zlib-devel 8 | # 下载 openssl 1.1.1 版本源码 9 | wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz 10 | tar zxvf openssl-1.1.1g.tar.gz 11 | cd openssl-1.1.1g 12 | # 开始编译 13 | ./config --prefix=/usr --openssldir=/etc/ssl --libdir=lib no-shared zlib-dynamic 14 | make && make install 15 | 16 | # 查看是否安装成功 17 | openssl version 18 | echo 'openssl install finish.' 19 | -------------------------------------------------------------------------------- /shell/kernel-upgrage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | # centos升级系统内核 4 | # 添加elrepo 5 | yum -y update 6 | #启用 ELRepo 仓库 7 | #导入ELRepo仓库的公共密钥 8 | rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org 9 | #安装ELRepo仓库的yum源 10 | yum install -y https://www.elrepo.org/elrepo-release-7.0-4.el7.elrepo.noarch.rpm 11 | #查看可用内核列表 12 | yum -y --disablerepo="*" --enablerepo="elrepo-kernel" list available 13 | #安装最新版本 14 | yum -y --disablerepo=\* --enablerepo=elrepo-kernel install kernel-lt.x86_64 15 | #打印当前系统可用内核 16 | awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg 17 | #生效序号为0的内核,也就是最新安装的那个 18 | grub2-set-default 0 19 | #reboot 需要手动重启才行 20 | -------------------------------------------------------------------------------- /shell/lesson/find.md: -------------------------------------------------------------------------------- 1 | # find 2 | 3 | 4 | ```bash 5 | # 找出 7 天前的文件并删除 6 | find ./ -maxdepth 1 -mtime +7 | xargs rm -rf 7 | ``` 8 | -------------------------------------------------------------------------------- /shell/lesson/read.md: -------------------------------------------------------------------------------- 1 | # Read 2 | 3 | 在 Bash 下我们可以通过其内部命令 read 接收用户来自键盘的输入,并可以将输入的内容赋值给一个变量。 4 | read 命令比较常用的语法格式如下所示: 5 | ```bash 6 | read [-p prompt] [variable1 variable2...] 7 | ``` 8 | -p 选项用于在尝试读取任何输入之前,显示 prompt(提示信息)的内容到标准错误输出。我们一般使用这一选项来指定提示用户输入哪些内容的信息。read 命令会每次从标准输入(或使用 -u 选项指定的文件描述符中)读取一行的内容,它会将第一个单词赋值给第一个变量 variable1,第二个单词赋值给第二个变量 variable2,依次类推。如果输入的单词数少于指定的变量数,那么剩下的 name 变量的值会被设为空,环境变量 IFS 中的字符被作为分隔符来将输入的内容分隔为单词。 9 | 10 | 11 | -------------------------------------------------------------------------------- /shell/lesson/变量默认值.md: -------------------------------------------------------------------------------- 1 | https://unix.stackexchange.com/questions/30470/what-does-mean-in-a-shell-script 2 | 3 | 常见用法 4 | ```shell 5 | ${KUBE_ALL_WITH_PREFIX:-"false"} 6 | ``` 7 | 读取变量 KUBE_ALL_WITH_PREFIX 的值,如果为空则设置为默认值 "false" 8 | -------------------------------------------------------------------------------- /shell/load.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 统计占用CPU高的进程 3 | LANG=C 4 | PATH=/sbin:/usr/sbin:/bin:/usr/bin 5 | interval=1 6 | length=86400 7 | for i in $(seq 1 $(expr ${length} / ${interval}));do 8 | date 9 | LANG=C ps -eT -o%cpu,pid,tid,ppid,comm | grep -v CPU | sort -n -r | head -20 10 | date 11 | LANG=C cat /proc/loadavg 12 | { LANG=C ps -eT -o%cpu,pid,tid,ppid,comm | sed -e 's/^ *//' | tr -s ' ' | grep -v CPU | sort -n -r | cut -d ' ' -f 1 | xargs -I{} echo -n "{} + " && echo ' 0'; } | bc -l 13 | sleep ${interval} 14 | done 15 | fuser -k $0 -------------------------------------------------------------------------------- /shell/loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [ "$1" = '' ]; then 6 | while true; do sleep 1000; done 7 | fi 8 | 9 | exec "$@" 10 | -------------------------------------------------------------------------------- /shell/oom_score.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | printf 'PID\tOOM Score\tOOM Adj\tCommand\n' 3 | while read -r pid comm; do [ -f /proc/$pid/oom_score ] && [ $(cat /proc/$pid/oom_score) != 0 ] && printf '%d\t%d\t\t%d\t%s\n' "$pid" "$(cat /proc/$pid/oom_score)" "$(cat /proc/$pid/oom_score_adj)" "$comm"; done < <(ps -e -o pid= -o comm=) | sort -k 2nr 4 | -------------------------------------------------------------------------------- /storage/elasticsearch/search/key.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | // Index ES索引结构 index+type 4 | type Index struct { 5 | Index string // 索引名 6 | Type string // 文档类型 新版固定为`doc` 7 | } 8 | 9 | // ESite es中网址的具体结构 10 | type ESite struct { 11 | ID string `json:"id"` // _id 12 | Keywords []string `json:"keywords"` // 关键字 13 | Host string `json:"host"` // 域名 14 | } 15 | -------------------------------------------------------------------------------- /storage/mysql/gorm/model/user.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "database/sql" 5 | "time" 6 | 7 | "gorm.io/gorm" 8 | ) 9 | 10 | type User struct { 11 | gorm.Model 12 | Name string 13 | Age sql.NullInt64 14 | Birthday *time.Time 15 | Email string `gorm:"type:varchar(100);unique_index"` 16 | Role string `gorm:"size:255"` // 设置字段大小为255 17 | MemberNumber *string `gorm:"unique;not null"` // 设置会员号(member number)唯一并且不为空 18 | Num int `gorm:"AUTO_INCREMENT"` // 设置 num 为自增类型 19 | Address string `gorm:"index:addr"` // 给address字段创建名为addr的索引 20 | IgnoreMe int `gorm:"-"` // 忽略本字段 21 | } 22 | -------------------------------------------------------------------------------- /storage/postgresql/constant/constant.go: -------------------------------------------------------------------------------- 1 | package constant 2 | 3 | const ( 4 | UserName = "postgres" 5 | Password = "root" 6 | Addr = "192.168.0.2:5432" 7 | Database = "t" 8 | ) 9 | -------------------------------------------------------------------------------- /storage/postgresql/util/handerror.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | func HandError(msg string, err error) { 8 | if err != nil { 9 | log.Printf("msg:%s err:%v", msg, err) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /storage/redis/cache-cross.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /*// get 伪代码 互斥锁 防止缓存击穿问题 建议使用 singleflight 库 4 | func get(key string) { 5 | ret := redis.get(Key) 6 | if ret == nil { // 为空代表缓存值过期 7 | // 获取锁 同时设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db 8 | setMutex := redis.setnx(key_mutex, 1, 3*60) == 1 9 | if setMutex { 10 | // 成功获取锁则load db并回设到缓存 11 | value = db.get(key) 12 | redis.set(key, value, expire_secs) 13 | redis.del(key_mutex) 14 | } else { 15 | // 获取失败表示其他请求已经在load db并回设到缓存了 sleep一会然后重试 16 | time.Sleep(50) 17 | get(key) 18 | } 19 | } 20 | } 21 | */ 22 | -------------------------------------------------------------------------------- /storage/redis/hash/bloomhash_test.go: -------------------------------------------------------------------------------- 1 | package hash 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestBloomFilter_BloomHash(t *testing.T) { 9 | hash := NewBloomFilterHash(1000*10, 3) 10 | key := []byte("second") 11 | bloomHash := hash.BloomHash(key) 12 | fmt.Printf("res :%v\n", bloomHash) 13 | } 14 | 15 | func BenchmarkNewBloomFilterHash(b *testing.B) { 16 | for i := 0; i < b.N; i++ { 17 | hash := NewBloomFilterHash(1000*20, 3) 18 | key := []byte("second") 19 | _ = hash.BloomHash(key) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /storage/redis/lock/fake.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | const FirstLock = "firstlock" 4 | 5 | // 伪代码 6 | //func main() { 7 | // if getLock() { 8 | // defer releaseKey() 9 | // doSomething() 10 | // } 11 | //} 12 | // 13 | //func getLock() bool { 14 | // if existKey(FirstLock) { 15 | // return false 16 | // } else { 17 | // setKey(FirstLock) 18 | // return true 19 | // } 20 | //} 21 | //func releaseKey() { 22 | // if getKey(FirstLock) == randomValue { 23 | // deleteKey(FirstLock) 24 | // } 25 | //} 26 | -------------------------------------------------------------------------------- /storage/redis/redis_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "i-go/utils" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestConnRedis(t *testing.T) { 10 | defer utils.InitLog("redis")() 11 | time.Sleep(time.Second) 12 | } 13 | -------------------------------------------------------------------------------- /test/gc/gc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "runtime/trace" 6 | ) 7 | 8 | func main() { 9 | file, err := os.Create("trace.out") 10 | if err != nil { 11 | panic(err) 12 | } 13 | defer file.Close() 14 | err = trace.Start(file) 15 | if err != nil { 16 | panic(err) 17 | } 18 | defer trace.Stop() 19 | 20 | // your program here 21 | } 22 | -------------------------------------------------------------------------------- /test/maps/sync_map_benchmark_adapter.go: -------------------------------------------------------------------------------- 1 | package maps 2 | 3 | import "sync" 4 | 5 | func NewSyncMapBenchmarkAdapter() *SyncMapBenchmarkAdapter { 6 | return &SyncMapBenchmarkAdapter{} 7 | } 8 | 9 | type SyncMapBenchmarkAdapter struct { 10 | m sync.Map 11 | } 12 | 13 | func (m *SyncMapBenchmarkAdapter) Set(key interface{}, val interface{}) { 14 | m.m.Store(key, val) 15 | } 16 | 17 | func (m *SyncMapBenchmarkAdapter) Get(key interface{}) (interface{}, bool) { 18 | return m.m.Load(key) 19 | } 20 | 21 | func (m *SyncMapBenchmarkAdapter) Del(key interface{}) { 22 | m.m.Delete(key) 23 | } 24 | -------------------------------------------------------------------------------- /test/mock/user.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | ) 6 | 7 | //go:generate mockgen -source=user.go -destination=mock_user.go -package mock i-go/test/mock IUser 8 | type IUser interface { 9 | Get(id string) (User, error) 10 | } 11 | type User struct { 12 | Username string 13 | Password string 14 | } 15 | 16 | var ( 17 | ErrEmptyID = errors.New("id is empty") 18 | ErrUserNotFond = errors.New("user not found") 19 | ) 20 | 21 | func QueryUser(db IUser, id string) (User, error) { 22 | if id == "" { 23 | return User{}, ErrEmptyID 24 | } 25 | return db.Get(id) 26 | } 27 | -------------------------------------------------------------------------------- /test/pprof/continuous-profiling/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | func Test_fib(t *testing.T) { 6 | for i := 0; i < 30; i++ { 7 | f := fib(i) 8 | t.Logf("fib(%d) = %d", i, f) 9 | } 10 | } 11 | 12 | func BenchmarkFib(b *testing.B) { 13 | for i := 0; i < b.N; i++ { 14 | fib(35) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/slice/slice.go: -------------------------------------------------------------------------------- 1 | package slice 2 | 3 | /* 4 | // go 性能分析 https://geektutu.com/post/hpg-slice.html 5 | 在已有切片的基础上进行切片,不会创建新的底层数组。因为原来的底层数组没有发生变化,内存会一直占用,直到没有变量引用该数组。 6 | 因此很可能出现这么一种情况,原切片由大量的元素构成,但是我们在原切片的基础上切片,虽然只使用了很小一段,但底层数组在内存中仍然占据了大量空间,得不到释放。 7 | 比较推荐的做法,使用 copy 替代 re-slice。 8 | */ 9 | func lastNumsBySlice(origin []int) []int { 10 | return origin[len(origin)-2:] 11 | } 12 | 13 | func lastNumsByCopy(origin []int) []int { 14 | result := make([]int, 2) 15 | copy(result, origin[len(origin)-2:]) 16 | return result 17 | } 18 | -------------------------------------------------------------------------------- /test/unittest/01-sum.go: -------------------------------------------------------------------------------- 1 | package unittest 2 | 3 | func Sum(a, b int) int { 4 | return a + b 5 | } 6 | -------------------------------------------------------------------------------- /test/unittest/01-sum_test.go: -------------------------------------------------------------------------------- 1 | package unittest 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test_Sum(t *testing.T) { 8 | s := Sum(1, 1) 9 | if s != 2 { 10 | t.Fatalf("sum(1,1) failed. Got %d, expected 2.", s) 11 | } 12 | } 13 | 14 | func BenchmarkFor(b *testing.B) { 15 | for i := 0; i < b.N; i++ { 16 | // 差不过50ms 17 | for j := 0; j < 1_0000_0000; j++ { 18 | } 19 | } 20 | } 21 | 22 | func TestA(t *testing.T) { 23 | // 差不过50ms 24 | for { 25 | for j := 0; j < 1_0000_0000; j++ { 26 | if j%100_0000 == 0 { 27 | // time.Sleep(time.Millisecond) 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/unittest/doc.go: -------------------------------------------------------------------------------- 1 | package unittest 2 | 3 | // go 单元测试 4 | -------------------------------------------------------------------------------- /tips/filter/filter.go: -------------------------------------------------------------------------------- 1 | // pipeline-filter 模式 2 | package filter 3 | 4 | type Request interface{} 5 | type Response interface{} 6 | 7 | type IFilter interface { 8 | Process(data Request) (Response, error) 9 | } 10 | -------------------------------------------------------------------------------- /tips/filter/split_filter.go: -------------------------------------------------------------------------------- 1 | package filter 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | type SplitFilter struct { 9 | delimiter string 10 | } 11 | 12 | var SplitFilterWongFormatError = errors.New("input data should be string") 13 | 14 | func NewSplitFilter(delimiter string) *SplitFilter { 15 | return &SplitFilter{delimiter: delimiter} 16 | } 17 | 18 | func (sf *SplitFilter) Process(data Request) (Response, error) { 19 | str, ok := data.(string) 20 | if !ok { 21 | return nil, SplitFilterWongFormatError 22 | } 23 | parts := strings.Split(str, sf.delimiter) 24 | return parts, nil 25 | } 26 | -------------------------------------------------------------------------------- /tips/filter/straight_piple.go: -------------------------------------------------------------------------------- 1 | package filter 2 | 3 | type StraightPipeline struct { 4 | Name string 5 | Filters []IFilter 6 | } 7 | 8 | func NewStraightPipeline(name string, filters ...IFilter) *StraightPipeline { 9 | return &StraightPipeline{ 10 | Name: name, 11 | Filters: filters, 12 | } 13 | } 14 | 15 | func (f *StraightPipeline) Process(data Request) (Response, error) { 16 | var ( 17 | ret interface{} 18 | err error 19 | ) 20 | for _, filter := range f.Filters { 21 | ret, err = filter.Process(data) 22 | if err != nil { 23 | return ret, err 24 | } 25 | data = ret 26 | } 27 | return ret, nil 28 | } 29 | -------------------------------------------------------------------------------- /tips/filter/straight_piple_test.go: -------------------------------------------------------------------------------- 1 | package filter 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestStraightPipeline_Process(t *testing.T) { 8 | spliter := NewSplitFilter(",") 9 | converter := NewToIntFilter() 10 | sum := NewSumFilter() 11 | sp := NewStraightPipeline("P1", spliter, converter, sum) 12 | ret, err := sp.Process("1,2,3") 13 | if err != nil { 14 | t.Fatal(err) 15 | } 16 | if ret != 6 { 17 | t.Fatalf("The excepted is 6, but the actual is %d", ret) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tips/filter/sum_filter.go: -------------------------------------------------------------------------------- 1 | package filter 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | type SumFilter struct { 8 | } 9 | 10 | var SumFilterWongFormatError = errors.New("input data should be int array") 11 | 12 | func NewSumFilter() *SumFilter { 13 | return &SumFilter{} 14 | } 15 | 16 | func (sf *SumFilter) Process(data Request) (Response, error) { 17 | parts, ok := data.([]int) 18 | if !ok { 19 | return nil, ToIntFilterWongFormatError 20 | } 21 | var ret int 22 | for _, elem := range parts { 23 | ret += elem 24 | } 25 | return ret, nil 26 | } 27 | -------------------------------------------------------------------------------- /tips/filter/to_int_filter.go: -------------------------------------------------------------------------------- 1 | package filter 2 | 3 | import ( 4 | "errors" 5 | "strconv" 6 | ) 7 | 8 | type ToIntFilter struct { 9 | } 10 | 11 | var ToIntFilterWongFormatError = errors.New("input data should be string array") 12 | 13 | func NewToIntFilter() *ToIntFilter { 14 | return &ToIntFilter{} 15 | } 16 | 17 | func (tif *ToIntFilter) Process(data Request) (Response, error) { 18 | parts, ok := data.([]string) 19 | if !ok { 20 | return nil, ToIntFilterWongFormatError 21 | } 22 | var ret []int 23 | for _, part := range parts { 24 | i, err := strconv.Atoi(part) 25 | if err != nil { 26 | return nil, err 27 | } 28 | ret = append(ret, i) 29 | } 30 | return ret, nil 31 | } 32 | -------------------------------------------------------------------------------- /tools/lock/interface.go: -------------------------------------------------------------------------------- 1 | package lock 2 | 3 | import "time" 4 | 5 | type ILock interface { 6 | Lock(key string, value interface{}, expire time.Duration) bool 7 | UnLock(key string, value interface{}) error 8 | } 9 | -------------------------------------------------------------------------------- /tools/pay/README.md: -------------------------------------------------------------------------------- 1 | 2 | 大致步骤 3 | 1)创建订单时先生成订单号,将订单信息以订单号为key存到缓存 4 | 2)调用支付宝(微信)支付接口,生成URL,放回前端 5 | 3)前端在新窗口打开URL,让用户进行支付,并在原页面轮询订单支付状态 6 | 4)支付后,在回调中写入具体逻辑,并将订单切换到支付成功状态 7 | 5)前端检测到订单已支付,弹出提示,到此支付流程结束。 8 | -------------------------------------------------------------------------------- /tools/pool/README.md: -------------------------------------------------------------------------------- 1 | Golang 实现的连接池 2 | 3 | Demo 4 | channel 实现和 slice 实现。 5 | 参考 6 | https://github.com/silenceper/pool 7 | https://juejin.cn/post/6844904077386596366 -------------------------------------------------------------------------------- /tools/pool/conn.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | // Conn 具体连接资源 4 | type Conn struct { 5 | Unix int64 6 | } 7 | 8 | func (c *Conn) Close() error { 9 | c.Unix = 0 10 | return nil 11 | } 12 | -------------------------------------------------------------------------------- /tools/pool/list_test.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func Test_List(t *testing.T) { 9 | num := 100_0000 10 | list := NewList(int64(num)) 11 | for i := 0; i < num; i++ { 12 | list.LPush([]interface{}{"A", "B", "C", "D", "E", "F"}) 13 | } 14 | for i := 0; i < num; i++ { 15 | fmt.Println(list.RPopLPush()) 16 | } 17 | } 18 | 19 | func BenchmarkName(b *testing.B) { 20 | num := 100_0000 21 | list := NewList(int64(num)) 22 | for i := 0; i < num; i++ { 23 | list.LPush([]interface{}{i}) 24 | } 25 | b.ResetTimer() 26 | for i := 0; i < b.N; i++ { 27 | list.RPopLPush() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tools/pool/pool.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | var ( 10 | // ErrClosed 连接池已经关闭Error 11 | ErrClosed = errors.New("pool is closed") 12 | // ErrPoolFull 连接池已满 13 | ErrPoolFull = errors.New("connection pool is full") 14 | // ErrConnCreateLimit 连接创建数达到连接池最大限制 15 | ErrConnCreateLimit = errors.New("connection create limit") 16 | ) 17 | 18 | // Pool 基本方法 只需要实现了 io.Closer 接口即可使用该连接池 19 | type Pool interface { 20 | Get() (io.Closer, error) 21 | 22 | Put(io.Closer) error 23 | 24 | Close() error 25 | 26 | Len() int 27 | } 28 | -------------------------------------------------------------------------------- /tools/region/README.md: -------------------------------------------------------------------------------- 1 | ip2region.db 下载 2 | # 百度云链接 链接:https://pan.baidu.com/s/180__IJ11q0ng5IDYgwXE3A 提取码:6666 3 | # 仓库地址 https://github.com/lionsoul2014/ip2region/tree/master/data 4 | GeoLite2-City.mmdb 下载 5 | # 下载链接(需登录): https://www.maxmind.com/en/accounts/576594/geoip/downloads 6 | -------------------------------------------------------------------------------- /tools/region/core/geo_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/spf13/viper" 8 | ) 9 | 10 | const ( 11 | LocalIP = "49.76.162.72" 12 | ) 13 | 14 | func TestMain(m *testing.M) { 15 | viper.Set("geo", "D:\\wlinno\\projects\\vaptcha-go\\conf\\region\\GeoLite2-City.mmdb") 16 | InitLatLong() 17 | m.Run() 18 | } 19 | 20 | func TestIP2LatLong(t *testing.T) { 21 | long, err := IP2LatLong(LocalIP) 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | t.Log(long) 26 | } 27 | 28 | func TestIP2RegionCN(t *testing.T) { 29 | cn := IP2RegionCN(LocalIP) 30 | en := IP2RegionEN(LocalIP) 31 | fmt.Println(cn, en) 32 | } 33 | -------------------------------------------------------------------------------- /tools/region/http/cmd/ip.http: -------------------------------------------------------------------------------- 1 | ### 经纬度 2 | GET http://localhost:8081/api/v1/tools/ip2latlong?ip=183.69.225.99 3 | Accept: application/json 4 | 5 | ### 区域 6 | GET http://localhost:8081/api/v1/tools/ip2region?ip=183.69.225.99 7 | Accept: application/json -------------------------------------------------------------------------------- /tools/region/http/cmd/region.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "i-go/core/conf" 7 | "i-go/tools/region/core" 8 | "i-go/tools/region/http/router" 9 | 10 | "github.com/gin-gonic/gin" 11 | ) 12 | 13 | func main() { 14 | err := conf.Load("conf/config_ip.yaml") 15 | if err != nil { 16 | panic(err) 17 | } 18 | core.InitRegion() 19 | core.InitLatLong() 20 | 21 | gin.SetMode(gin.ReleaseMode) 22 | engine := gin.New() 23 | engine.Use(gin.Recovery()) 24 | router.RegisterRegion(engine) 25 | fmt.Println("HTTP Server Is Running") 26 | if err := engine.Run(":8081"); err != nil { 27 | panic(err) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tools/region/http/controller/geo.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "net/http" 5 | 6 | "i-go/tools/region/core" 7 | 8 | "github.com/gin-gonic/gin" 9 | ) 10 | 11 | // Ip2LatLong ip 转经纬度 12 | func (ip2region) Ip2LatLong(c *gin.Context) { 13 | ip := c.Query("ip") 14 | if ip == "" { 15 | ip = c.ClientIP() 16 | } 17 | lagLong, err := core.IP2LatLong(ip) 18 | if err != nil { 19 | c.JSON(http.StatusOK, "查询失败"+err.Error()) 20 | } 21 | c.JSON(http.StatusOK, lagLong) 22 | } 23 | -------------------------------------------------------------------------------- /tools/region/http/controller/region.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "net/http" 5 | 6 | "i-go/tools/region/core" 7 | 8 | "github.com/gin-gonic/gin" 9 | ) 10 | 11 | type ip2region struct { 12 | } 13 | 14 | var Tools = &ip2region{} 15 | 16 | type IP struct { 17 | IP string `json:"ip"` 18 | Region string `json:"region"` 19 | } 20 | 21 | func (ip2region) Ip2Region(c *gin.Context) { 22 | ip := c.Query("ip") 23 | if ip == "" { 24 | ip = c.ClientIP() 25 | } 26 | reg := core.IP2Region(ip) 27 | ret := IP{ 28 | IP: ip, 29 | Region: reg, 30 | } 31 | c.JSON(http.StatusOK, ret) 32 | } 33 | -------------------------------------------------------------------------------- /tools/region/http/router/router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "i-go/tools/region/http/controller" 5 | 6 | "github.com/gin-gonic/gin" 7 | ) 8 | 9 | func RegisterRegion(e *gin.Engine) { 10 | tools := e.Group("/api/v1/tools/") 11 | tools.GET("/ip2region", controller.Tools.Ip2Region) 12 | tools.GET("/ip2latlong", controller.Tools.Ip2LatLong) 13 | } 14 | -------------------------------------------------------------------------------- /tools/region/rpc/proto/make.cmd: -------------------------------------------------------------------------------- 1 | protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative region.proto -------------------------------------------------------------------------------- /tools/region/rpc/proto/region.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package proto; 3 | option go_package = "i-go/tools/region/rpc/proto;proto"; 4 | 5 | service RegionServer { 6 | rpc IP2Region (IP) returns (Region) {} 7 | rpc IP2LatLong (IP) returns (LatLong) {} 8 | } 9 | 10 | message IP { 11 | string ip = 1; 12 | } 13 | 14 | message Region { 15 | string region = 1; 16 | } 17 | 18 | message LatLong{ 19 | double Latitude = 1; 20 | double Longitude = 2; 21 | } -------------------------------------------------------------------------------- /tools/region/util/distance_test.go: -------------------------------------------------------------------------------- 1 | package ip2latlong 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestEarthDistance(t *testing.T) { 9 | lat1 := 0.0 10 | long1 := 105.5577 11 | lat2 := 180.0 12 | long2 := 105.5577 13 | distance := EarthDistance(lat1, long1, lat2, long2) 14 | fmt.Printf("distance:%vm\n ", int64(distance)) 15 | // 周长 40009880 最大距离为周长的一半 16 | } 17 | 18 | // 90.1 ns/op 19 | func BenchmarkEarthDistance(b *testing.B) { 20 | lat1 := 29.5689 21 | long1 := 106.5577 22 | lat2 := 22.5318 23 | long2 := 114.1374 24 | b.ResetTimer() 25 | for i := 0; i < b.N; i++ { 26 | _ = EarthDistance(lat1, long1, lat2, long2) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tools/sensitive/dfa/dfa_test.go: -------------------------------------------------------------------------------- 1 | package dfa 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestDFA(t *testing.T) { 9 | dfa := NewDFA() 10 | 11 | dfa.Append([]rune("abd")) 12 | dfa.Append([]rune("bcd")) 13 | hasPrefix := dfa.HasPrefix("abc") 14 | fmt.Println("是否存在前缀:", hasPrefix) 15 | contains := dfa.Contains("abcd") 16 | fmt.Println("是否存在敏感词:", contains) 17 | search := dfa.Search("abcdef", MatchAll) 18 | fmt.Println("敏感词出现位置:", search) 19 | _, marked := dfa.Cover("abcdef", '*') 20 | fmt.Println("对敏感词进行标记:", marked) 21 | } 22 | -------------------------------------------------------------------------------- /tools/sensitive/doc.go: -------------------------------------------------------------------------------- 1 | package sensitive 2 | 3 | /*敏感字检测 4 | 基于 前缀(Trie)树实现的 DFA 算法 5 | */ 6 | -------------------------------------------------------------------------------- /tools/sitemap/generator.go: -------------------------------------------------------------------------------- 1 | package sitemap 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/ikeikeikeike/go-sitemap-generator/v2/stm" 7 | ) 8 | 9 | func GenerateSitemap(path string) { 10 | sm := stm.NewSitemap(1) 11 | // Your website's host name 12 | sm.SetDefaultHost("https://www.lixueduan.com") 13 | sm.SetVerbose(true) 14 | sm.SetCompress(false) 15 | sm.SetPretty(true) 16 | sm.SetFilename("sitemap") 17 | sm.SetPublicPath(path) // sitemap 生成文件输出路径,会再该路径下生成 /sitemaps 目录 18 | sm.Create() 19 | date := time.Now().Format("2006-01-02") 20 | url := stm.URL{{"loc", "https://www.lixueduan.com"}, {"lastmod", date}} 21 | sm.Add(url) 22 | sm.Finalize() 23 | } 24 | -------------------------------------------------------------------------------- /tools/sitemap/generator_test.go: -------------------------------------------------------------------------------- 1 | package sitemap 2 | 3 | import "testing" 4 | 5 | func TestGenerateSitemap(t *testing.T) { 6 | GenerateSitemap("./") 7 | } 8 | -------------------------------------------------------------------------------- /training/engineering/api/design.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package go_protoc; 3 | // 新版插件中 必须 配置 option go_package = "xxx"; 4 | //推荐阅读:[谷歌API设计指南](https://cloud.google.com/apis/design?hl=zh-cn) 5 | option go_package = "/pb"; 6 | 7 | service LibraryService { 8 | rpc UpdateBook ( UpdateBookRequest) returns ( Book) ; 9 | } 10 | message UpdateBookRequest { 11 | Book book = 1; 12 | google.protobuf.FieldMask mask = 2; 13 | } 14 | 15 | message Book { 16 | // The name is ignored when creating a book. 17 | string name = 1 ; 18 | string author = 2; 19 | string title = 3; 20 | bool read = 4; // Users report they get bored 21 | } -------------------------------------------------------------------------------- /training/engineering/dip.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | ) 6 | 7 | // 依赖倒置原则(Dependence Inversion Principle) 8 | // 依赖注入 9 | 10 | // IService 上层只依赖接口(抽象)而不依赖实现(具象) 11 | type IService interface { 12 | Query(id int) (string, error) 13 | } 14 | 15 | type Service struct { 16 | db *sql.DB 17 | } 18 | 19 | // NewService 通道外部传入db对象来实现依赖倒置 20 | func NewService(db *sql.DB) IService { 21 | return &Service{db: db} 22 | } 23 | 24 | func (s *Service) Query(id int) (string, error) { 25 | // s.db.Query() 26 | return "", nil 27 | } 28 | -------------------------------------------------------------------------------- /training/engineering/wire/wire.go: -------------------------------------------------------------------------------- 1 | // The build tag makes sure the stub is not built in the final build. 2 | //go:build wireinject 3 | // +build wireinject 4 | 5 | package main 6 | 7 | import "github.com/google/wire" 8 | 9 | // InitializeEvent creates an Event. It will error if the Event is staffed with 10 | // a grumpy greeter. 11 | func InitializeEvent(phrase string) (Event, error) { 12 | wire.Build(NewEvent, NewGreeter, NewMessage) 13 | return Event{}, nil 14 | } 15 | -------------------------------------------------------------------------------- /training/engineering/wire/wire_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by Wire. DO NOT EDIT. 2 | 3 | //go:generate go run github.com/google/wire/cmd/wire 4 | //go:build !wireinject 5 | // +build !wireinject 6 | 7 | package main 8 | 9 | // Injectors from wire.go: 10 | 11 | // InitializeEvent creates an Event. It will error if the Event is staffed with 12 | // a grumpy greeter. 13 | func InitializeEvent(phrase string) (Event, error) { 14 | message := NewMessage(phrase) 15 | greeter := NewGreeter(message) 16 | event, err := NewEvent(greeter) 17 | if err != nil { 18 | return Event{}, err 19 | } 20 | return event, nil 21 | } 22 | -------------------------------------------------------------------------------- /training/error/pgkerrors.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | xerrors "github.com/pkg/errors" 8 | ) 9 | 10 | var errMy = errors.New("my") 11 | 12 | func main() { 13 | err := test2() 14 | fmt.Printf("main: %+v\n", err) 15 | } 16 | func test0() error { 17 | return xerrors.Wrapf(errMy, "test0 failed") 18 | } 19 | func test1() error { 20 | return test0() 21 | } 22 | func test2() error { 23 | return test1() 24 | } 25 | -------------------------------------------------------------------------------- /training/goroutine/4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import _ "go.uber.org/automaxprocs" 4 | 5 | // github.com/uber-go/automaxprocs 容器环境 自动配置 maxprocs 6 | func main() { 7 | // 自动获取cgroup中的数据来设置maxprocess 8 | // 具体为 cpu.cfs_quota_us / cpu.cfs_period_us 9 | } 10 | -------------------------------------------------------------------------------- /training/memory-model/a.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 18 | 19 | -------------------------------------------------------------------------------- /training/memory-model/reordering.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "time" 4 | 5 | func main() { 6 | var ( 7 | A, B int 8 | ) 9 | go func() { 10 | A = 1 11 | print(B) 12 | }() 13 | 14 | go func() { 15 | B = 1 16 | print(A) 17 | }() 18 | time.Sleep(time.Second) 19 | } 20 | -------------------------------------------------------------------------------- /training/network/demo/udp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "runtime" 7 | ) 8 | 9 | func main() { 10 | listen, err := net.ListenUDP("udp", &net.UDPAddr{Port: 20000}) 11 | if err != nil { 12 | log.Fatalf("listen error: %v\n", err) 13 | } 14 | defer listen.Close() 15 | for { 16 | var buf [1024]byte 17 | n, addr, err := listen.ReadFromUDP(buf[:]) 18 | if err != nil { 19 | log.Printf("read udp error: %v\n", err) 20 | continue 21 | } 22 | runtime.GC() 23 | data := append([]byte("hello "), buf[:n]...) 24 | _, _ = listen.WriteToUDP(data, addr) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /training/package-context/withvalue.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | ctx1 := context.WithValue(context.Background(), "k1", "v1") 10 | ctx2 := context.WithValue(ctx1, "k1", "v11") 11 | value := ctx2.Value("k1") 12 | fmt.Println(value) 13 | } 14 | -------------------------------------------------------------------------------- /training/package-sync/1-compilation.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var counter int 6 | 7 | // go tool compile -S 1-compilation.go 8 | /* 9 | counter++ 并不是原子操作,底层是分3步完成: 10 | MOVQ "".counter(SB), AX // 1.将counter的值赋给AX 11 | INCQ AX // 2. AX 自增 12 | MOVQ AX, "".counter(SB) // 3. 将AX的值赋给counter 13 | */ 14 | func main() { 15 | counter++ 16 | fmt.Println(counter) 17 | } 18 | -------------------------------------------------------------------------------- /training/runtime/memory/escape.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | ) 7 | 8 | // go build -gcflags -m escape.go 9 | 10 | func main() { 11 | num := getRandom() 12 | fmt.Println(num) 13 | } 14 | 15 | // go:noinline 禁止内联优化,用于测试逃逸分析 16 | func getRandom() *int64 { 17 | tmp := rand.Int63() 18 | return &tmp 19 | } 20 | -------------------------------------------------------------------------------- /utils/base64.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | // AddBase64Header 图片base64编码 添加Header 8 | // completeBase64-->data:image/png;base64,iVBORw0KGgo... 9 | func AddBase64Header(base64Body, contentType string) (completeBase64 string) { 10 | str := []string{"data:", contentType, ";base64,", base64Body} 11 | completeBase64 = strings.Join(str, "") 12 | return completeBase64 13 | } 14 | 15 | // TrimBase64Header 移除Base64头 16 | // data:image/png;base64,iVBORw0KGgo... 去掉`,`之前的部分 17 | func TrimBase64Header(completeBase64 string) (base64Body string) { 18 | index := strings.Index(completeBase64, ",") 19 | base64Body = completeBase64[index+1:] 20 | return base64Body 21 | } 22 | -------------------------------------------------------------------------------- /utils/bloom/bloom_filter_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/willf/bloom" 7 | ) 8 | 9 | func BenchmarkBloom(b *testing.B) { 10 | filter := bloom.New(20000000, 5) 11 | filter.Add([]byte("Golang")) // 添加数据 12 | b.ResetTimer() 13 | for i := 0; i < b.N; i++ { 14 | _ = filter.Test([]byte("Golang")) // 测试是否存在 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /utils/container-test/redis_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | -------------------------------------------------------------------------------- /utils/convert/bytes_string.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | // Bytes和String高效转换 4 | import ( 5 | "reflect" 6 | "unsafe" 7 | ) 8 | 9 | func Bytes2String(b []byte) string { 10 | return *(*string)(unsafe.Pointer(&b)) 11 | } 12 | 13 | func String2Bytes(str string) []byte { 14 | sh := (*reflect.SliceHeader)(unsafe.Pointer(&str)) 15 | // slice 比 string 多一个 cap 属性 这里给 cap 单独赋值 16 | sh.Cap = sh.Len 17 | return *(*[]byte)(unsafe.Pointer(sh)) 18 | } 19 | -------------------------------------------------------------------------------- /utils/hotrank/hotrank.go: -------------------------------------------------------------------------------- 1 | // Package hotrank 热度排名算法 2 | package hotrank 3 | 4 | import ( 5 | "math" 6 | ) 7 | 8 | const ( 9 | // 常数e 10 | e = 2.71828 11 | // cd 冷却系数 12 | cd = 0.192 13 | ) 14 | 15 | // NewtonsLawOfCooling 牛顿冷却定律 公式 T=T0*e^{-α*(t-t0) 16 | /* 17 | // 笔记链接 https://github.com/lixd/daily-notes/blob/master/DataStructuresandAlgorithms/%E7%83%AD%E5%BA%A6TopN%E6%8E%92%E5%90%8D%E7%AE%97%E6%B3%95.md 18 | latestScore 上次得分或热度 19 | dt 间隔时间(小时) 20 | 100分在24小时后冷却到1分 21 | */ 22 | func NewtonsLawOfCooling(latestScore, dt float64) float64 { 23 | index := -1 * cd * dt 24 | score := latestScore * math.Pow(e, index) 25 | return score 26 | } 27 | -------------------------------------------------------------------------------- /utils/hotrank/hotrank_test.go: -------------------------------------------------------------------------------- 1 | package hotrank 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestNewtonsLawOfCooling(t *testing.T) { 9 | cooling := NewtonsLawOfCooling(100, 24) 10 | fmt.Println(cooling) 11 | } 12 | -------------------------------------------------------------------------------- /utils/html_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | const WithHTML = `

买了个正版的刺客信条英灵殿,但是一进入游戏3分钟左右就闪退,无论在线还是离线模式,而且各种贴图错误。CPU、显卡性能是没有问题的,1080ti。 然后我下了个破解版的刺客信条奥德赛就能正常玩,太讽刺了。

网上找了很多方法都不行,包括重装1903的系统,重装稳定版的显卡驱动等等。。。求靠谱的解决方案,百度复制粘贴的就免了。

` 9 | 10 | func TestRemoveHTML(t *testing.T) { 11 | r := TrimHTML(WithHTML) 12 | fmt.Println(r) 13 | } 14 | 15 | func BenchmarkTrimHTML(b *testing.B) { 16 | for i := 0; i < b.N; i++ { 17 | _ = TrimHTML(WithHTML) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /utils/httputil/http.go: -------------------------------------------------------------------------------- 1 | package httputil 2 | 3 | import "net/url" 4 | 5 | // IsValidURL return true if input is a full and valid url,e.g. https://kubeclipper.io 6 | func IsValidURL(urlStr string) bool { 7 | _, err := url.ParseRequestURI(urlStr) 8 | if err != nil { 9 | return false 10 | } 11 | u, err := url.Parse(urlStr) 12 | if err != nil || u.Scheme == "" || u.Host == "" { 13 | return false 14 | } 15 | return true 16 | } 17 | -------------------------------------------------------------------------------- /utils/ratelimit/doc.go: -------------------------------------------------------------------------------- 1 | package ratelimit 2 | 3 | /* 4 | 限流算法常见的包括 leakyBucket 和 tokenBucket,以下几个实现用的比较多: 5 | leakyBucket: go.uber.org/ratelimit 6 | tokenBucket: golang.org/x/time/rate 7 | 当前比较推荐的是 自适应限流算法。 8 | 参考:https://www.jianshu.com/p/60fa376b9849 9 | 源码:https://github.com/go-kratos/aegis/tree/main/ratelimit/bbr 10 | kratos文档:https://github.com/go-kratos/kratos/blob/v1.0.x/docs/ratelimit.md 11 | Sentinel文档:https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81 12 | */ 13 | -------------------------------------------------------------------------------- /utils/ratelimit/simple_count_test.go: -------------------------------------------------------------------------------- 1 | package ratelimit 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestNewRequestLimitService(t *testing.T) { 10 | rater := NewRateLimiter(time.Second, 10) 11 | for i := 0; i < 100; i++ { 12 | if rater.AllowN(2) { 13 | fmt.Printf("通过 当前请求数:%v \n", rater.ReqCount()) 14 | } else { 15 | fmt.Println("wait...") 16 | time.Sleep(time.Millisecond * 500) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /utils/string_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "testing" 7 | ) 8 | 9 | func TestSubset(t *testing.T) { 10 | backends := make([]string, 0, 100) 11 | for i := 0; i < 100; i++ { 12 | backends = append(backends, strconv.Itoa(i)) 13 | } 14 | subset := Subset(backends, "client011", 10) 15 | fmt.Printf("%#v\n", subset) 16 | } 17 | 18 | func Test_stringHelper_GetUUID(t *testing.T) { 19 | for i := 0; i < 10; i++ { 20 | uuid := StringHelper.GetUUID() 21 | fmt.Println(uuid) 22 | } 23 | } 24 | --------------------------------------------------------------------------------