{"id":23213664,"url":"https://github.com/amirhnajafiz/generics","last_synced_at":"2025-08-19T05:33:08.663Z","repository":{"id":76922890,"uuid":"470722083","full_name":"amirhnajafiz/generics","owner":"amirhnajafiz","description":"Getting into Golang 1.18","archived":false,"fork":false,"pushed_at":"2022-08-28T18:19:44.000Z","size":69,"stargazers_count":14,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-12-16T22:03:04.107Z","etag":null,"topics":["fuzzing","generic","go","golang","golang-18","testing"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/amirhnajafiz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-03-16T19:21:04.000Z","updated_at":"2024-07-28T06:36:34.000Z","dependencies_parsed_at":"2023-08-10T03:48:11.944Z","dependency_job_id":"9685e0ba-864f-4e75-83af-39e8a1e9fa8e","html_url":"https://github.com/amirhnajafiz/generics","commit_stats":null,"previous_names":["amirhnajafiz/generics","amirhnajafiz/golang-18"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amirhnajafiz%2Fgenerics","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amirhnajafiz%2Fgenerics/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amirhnajafiz%2Fgenerics/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amirhnajafiz%2Fgenerics/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/amirhnajafiz","download_url":"https://codeload.github.com/amirhnajafiz/generics/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230326779,"owners_count":18209050,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fuzzing","generic","go","golang","golang-18","testing"],"created_at":"2024-12-18T19:18:25.650Z","updated_at":"2024-12-18T19:18:26.093Z","avatar_url":"https://github.com/amirhnajafiz.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./assets/logo.avif\" alt=\"logo\" width=\"400\" /\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003e\nGolang 1.18\n\u003c/h1\u003e\n\nNew features of Golang 1.18 with tutorial and examples.\nIn this repository I introduce new features of Golang version 1.18 with their examples and resources.\n\n## Contents\n- [Introduction](#introduction)\n    - [Generics](#getting-started-with-generics)\n    - [Fuzzing](#getting-started-with-fuzzing)\n    - [Workspace](#getting-started-with-multi-module-workspaces)\n    - [Performance Improvements](#20-performance-improvements)\n- Examples\n    - [Implement **Stack** with Generics](#stack)\n    - [Implement **Linkedlist** with Generics](#linked-list)\n    - [Implement **BinaryTree** with Generics](#binary-tree)\n- [Resources](#resources)\n- [Examples and Tutorials](#examples-and-tutorials)\n\n## Introduction\nThe latest Go release, version 1.18, is a significant release, including changes to the language, implementation of the toolchain, runtime, and libraries. Go 1.18 arrives seven months after Go 1.17. As always, the release maintains the Go 1 promise of compatibility. We expect almost all Go programs to continue to compile and run as before.\n\n### Getting started with generics\nTo support values of either type, that single function will need a way to declare what types it supports. To support this, you’ll write a function that declares type parameters in addition to its ordinary function parameters. These type parameters make the function generic, enabling it to work with arguments of different types. You’ll call the function with type arguments and ordinary function arguments. While a type parameter’s constraint typically represents a set of types, at compile time the type parameter stands for a single type – the type provided as a type argument by the calling code. If the type argument’s type isn’t allowed by the type parameter’s constraint, the code won’t compile.\n\nExample:\n```go\n// SumIntsOrFloats sums the values of map m. It supports both int64 and float64\n// as types for map values.\nfunc SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {\n    var s V\n    for _, v := range m {\n        s += v\n    }\n    return s\n}\n```\n\n```go\nSumIntsOrFloats[string, int64](ints)\nSumIntsOrFloats[string, float64](floats))\n```\n\nYou can omit type arguments in calling code when the Go compiler can infer the types you want to use. The compiler infers type arguments from the types of function arguments.\n\nNote that this isn’t always possible. For example, if you needed to call a generic function that had no arguments, you would need to include the type arguments in the function call.\n```go\nSumIntsOrFloats(ints)\nSumIntsOrFloats(floats))\n```\n\n#### Declare a type constraint\nYou declare a type constraint as an interface. The constraint allows any type implementing the interface. For example, if you declare a type constraint interface with three methods, then use it with a type parameter in a generic function, type arguments used to call the function must have all of those methods.\n```go\ntype Number interface {\n    int64 | float64\n}\n\nfunc SumNumbers[K comparable, V Number](m map[K]V) V {\n    var s V\n    for _, v := range m {\n        s += v\n    }\n    return s\n}\n```\n\nSee the [source code](./examples/generics/) of the example.\n\n### Getting started with fuzzing\nFuzzing, sometimes also called fuzz testing, is the practice of giving unexpected input to your software. Ideally, this test causes your application to crash, or behave in unexpected ways. Regardless of what happens, you can learn a lot from how your code reacts to data it wasn't programmed to accept, and you can add appropriate error handling.\n\nFuzzing is a technique where you automagically generate input values for your functions to find bugs.\nThe unit test has limitations, namely that each input must be added to the test by the developer. One benefit of fuzzing is that it comes up with inputs for your code, and may identify edge cases that the test cases you came up with didn’t reach.\n\nGeneral:\n```go\nfunc FuzzXXX(f *testing.F) {\n    f.Add() // Adding your own inputs if you want\n    f.Fuzz(func(t *testing.T) {\n        // Write your tests\n    })\n}\n```\n\nNow run your tests:\n```go\ngo test -fuzz=Fuzz\n```\n\nExample:\n```go\nfunc FuzzReverse(f *testing.F) {\n    testcases := []string{\"Hello, world\", \" \", \"!12345\"}\n    for _, tc := range testcases {\n        f.Add(tc)  // Use f.Add to provide a seed corpus\n    }\n\n    f.Fuzz(func(t *testing.T, orig string) {\n        rev := Reverse(orig)\n        doubleRev := Reverse(rev)\n        if orig != doubleRev {\n            t.Errorf(\"Before: %q, after: %q\", orig, doubleRev)\n        }\n        if utf8.ValidString(orig) \u0026\u0026 !utf8.ValidString(rev) {\n            t.Errorf(\"Reverse produced invalid UTF-8 string %q\", rev)\n        }\n    })\n}\n```\n\nWhen fuzzing, you can’t predict the expected output, since you don’t have control over the inputs.\u003cbr /\u003e\nNote the syntax differences between the unit test and the fuzz test:\n- The function begins with FuzzXxx instead of TestXxx, and takes \\*testing.F instead of \\*testing.T\n- Where you would expect to a see a t.Run execution, you instead see f.Fuzz which takes a fuzz target function whose parameters are \\*testing.T and the types to be fuzzed. The inputs from your unit test are provided as seed corpus inputs using f.Add.\n\nSee the [source code](./examples/fuzzing/) of the example.\n\n### Getting started with multi-module workspaces\nA workspace is a collection of modules on disk that are used as the root modules when running minimal version selection (MVS).\n\nA workspace can be declared in a go.work file that specifies relative paths to the module directories of each of the modules in the workspace. When no go.work file exists, the workspace consists of the single module containing the current directory.\n\nMost go subcommands that work with modules operate on the set of modules determined by the current workspace. go mod init, go mod why, go mod edit, go mod tidy, go mod vendor, and go get always operate on a single main module.\n\nWith multi-module workspaces, you can tell the Go command that you’re writing code in multiple modules at the same time and easily build and run code in those modules.\n\nInitialize the workspace:\n```shell\ngo work init [Directory name]\n```\nThe go.work file has similar syntax to **go.mod**, the go directive tells Go which version of Go the file should be interpreted with. It’s similar to the go directive in the go.mod file. The use directive tells Go that the module in the given directory should be main modules when doing a build.\n\nThe go work init command tells go to create a go.work file for a workspace containing the modules in the given directory.\u003cbr /\u003e\nThe go command produces a go.work file that looks like this:\n```go\ngo 1.18\n\nuse (\n    ./[Workspace/directory name]\n)\n```\n\nCreating workspaces:\n```shell\ngo work init ./mod ./tools\n```\n\nThe output project structur will be:\n```\nProject\n├── mod\n│   ├── go.mod      \n│   └── main.go\n├── go.work         \n└── tools\n    ├── fish.go\n    └── go.mod      \n```\n\nThe content of **go.work** file:\n```go\ngo 1.18\n\nuse (\n    ./mod \n    ./tools\n)\n```\n\nA total of three directives are supported within the go.work file:\n- go: declares the go version number, mainly for subsequent version control of new semantics.\n- use: declares the specific file path of a module on which the application depends. The path can be either absolute or relative, and can be outside the application’s destiny directory.\n- replace: Declares that the import path of a module dependency is replaced, with priority over the replace directive in go.mod.\n\nExample of **go.work** file with directives:\n```go\ngo 1.18\n\nuse (\n    ./baz // foo.org/bar/baz\n    ./tools // golang.org/x/tools\n)\n\nreplace golang.org/x/net =\u003e example.com/fork/net v1.4.5\n```\n\nThe go command has a couple of subcommands for working with workspaces in addition to go work init:\n- **go work use [-r] [dir]** adds a use directive to the go.work file for dir, if it exists, and removes the use directory if the argument directory doesn’t exist. The -r flag examines subdirectories of dir recursively.\n- **go work edit** edits the go.work file similarly to go mod edit\n- **go work sync** syncs dependencies from the workspace’s build list into each of the workspace modules.\n\nThe go.work file doesn’t need to be committed to a Git repository, otherwise it’s a bit of a toss-up. As long as you have go.work set up in your Go project, you will be in workspace mode at runtime and compile time, and the workspace configuration will be given highest priority to suit your local development needs.\n\nIf you want to disable workspace mode, you can specify it with the -workfile=off command.\n\nThat is, execute the following command at runtime.\n```shell\ngo run -workfile=off main.go\n\ngo build -workfile=off\n```\n\n### 20% Performance Improvements\nApple M1, ARM64, and PowerPC64 users rejoice! Go 1.18 includes CPU performance improvements of up to 20% due to the expansion of Go 1.17’s register ABI calling convention to these architectures. Just to underscore how big this release is, a 20% performance improvement is the fourth most important headline!\n\n## Examples\nIn this section I implemented some data structures with Golang generics.\n\n### Stack\nDefining the data types:\n```go\ntype Data interface {\n\tint64 | float64 | string\n}\n\ntype Node[T Data] struct {\n\tNext  *Node[T]\n\tValue T\n}\n\ntype Stack[T Data] struct {\n\tHead *Node[T]\n}\n```\n\nNow we can create our stack in any type we want:\n```go\ns := Stack[int64]{}\ns.Push(12)\ns.Push(129)\ns.Push(160)\ntemp := s.Pop()\n```\n\nSee the [source code](./examples/example/stack/) of the example.\n\n### Linked List\nSame types, but different methods:\n```go\ntype Data interface {\n\tint64 | float64 | string\n}\n\ntype Node[T Data] struct {\n\tNext  *Node[T]\n\tValue T\n}\n\ntype LinkedList[T Data] struct {\n\tHead *Node[T]\n}\n```\n\nNow we can build our linked list on any type:\n```go\nl := LinkedList[float64]{}\nl.Add(12.1)\nl.Add(22.45)\nl.Add(0.75)\nl.Iterate()\nl.Remove(12.1)\n```\n\nSee the [source code](./examples/example/linked-list/) of the example.\n\n### Binary Tree\nType parameter and data structs:\n```go\ntype Data interface {\n\tint | int32 | int64 | float64\n}\n\ntype Node[T Data] struct {\n\tParent *Node[T]\n\tLeft   *Node[T]\n\tRight  *Node[T]\n\tkey    T\n}\n\ntype Tree[T Data] struct {\n\tRoot *Node[T]\n}\n```\n\nNow we can create our tree with each type we want:\n```go\ntree := Tree[int]{}\ntree.Insert(20)\ntree.Insert(25)\ntree.Insert(24)\ntree.Delete(20)\n```\n\nSee the [source code](./examples/example/binary-tree/) of the example.\n\n## Resources\n- [Beta installation of Go 1.18](https://go.dev/blog/go1.18beta2)\n- [Whats new in Go 1.18](https://go.dev/blog/go1.18)\n- [All new in Go 1.18](https://tip.golang.org/doc/go1.18)\n- [Go workspace](https://go.dev/ref/mod#workspaces)\n- [Go 1.18 overview](https://www.youtube.com/watch?v=-wpISpghaB8)\n- [Multi-Module Workspace](https://go.googlesource.com/proposal/+/master/design/45713-workspace.md)\n- [Go multi-module](https://www.sobyte.net/post/2022-01/go-multi-module/)\n\n## Examples and Tutorials\n- [Go generics tutorial](https://go.dev/doc/tutorial/generics)\n- [Go fuzzings tutorial](https://go.dev/doc/tutorial/fuzz)\n- [Go workspace tutorial](https://go.dev/doc/tutorial/workspaces)\n- [Go examples for generics](https://www.google.com/url?sa=t\u0026rct=j\u0026q=\u0026esrc=s\u0026source=web\u0026cd=\u0026cad=rja\u0026uact=8\u0026ved=2ahUKEwjagPy1is_2AhXP8rsIHUWABXQQFnoECAgQAQ\u0026url=https%3A%2F%2Fbignerdranch.com%2Fblog%2Fexploring-go-v1-18s-generics%2F\u0026usg=AOvVaw0p24Y94Q3VshO1kUaKY_p7)\n- [Type parameters in Go 1.18](https://www.youtube.com/watch?v=Rvq__lVVmQc)\n- [First look at Go generics](https://www.youtube.com/watch?v=lw4X6takiRA)\n- [All you need to know about fuzzing testing in Go](https://opensource.com/article/22/1/native-go-fuzz-testing)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famirhnajafiz%2Fgenerics","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famirhnajafiz%2Fgenerics","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famirhnajafiz%2Fgenerics/lists"}