From 9c98a8e3c2794e3a2b6d085e9cb7787108d8745e Mon Sep 17 00:00:00 2001 From: a73x Date: Sun, 8 Dec 2024 20:27:32 +0000 Subject: new posts --- public/posts/2024-12-08-01.html | 101 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 public/posts/2024-12-08-01.html (limited to 'public/posts/2024-12-08-01.html') diff --git a/public/posts/2024-12-08-01.html b/public/posts/2024-12-08-01.html new file mode 100644 index 0000000..919339c --- /dev/null +++ b/public/posts/2024-12-08-01.html @@ -0,0 +1,101 @@ + + + + + + + + + + a73x + + + + + +
+

a73x

+ high effort, low reward + + +

Simplifying Interfaces with Function Types

+

In Go, you can define methods on type aliases, which means that we can define a type alias of a function, and then define methods on that function.

+ +

Example

+ +

Given the following interface

+
type DB interface {
+	Get(string) (string, error)
+}
+
+

You can fulfill it using a function type like this:

+
type GetFn func(string) (string, error)
+
+func (f GetFn) Get(a string) (string, error) {
+	return f(a)
+}
+
+

Now you can use GetFn whenever a DB is required:

+
func main() {
+	var storeFn DB = GetFn(func(s string) (string, error) {
+		return "bar", nil
+	})
+	fmt.Println(storeFn.Get("Foo")) // Outputs: bar
+}
+
+

You can try this example in this [Go Playground](https://go.dev/play/p/hyBNIMblafs

+ +

How it works

+ +

In Go, interfaces are implicitly through method sets, which means any type (including a function type) that defines the required methods satisfies the interface. By defining the Get method on the GetFn type, the compiler treats GetFn as a valid implementation of the DB interface.

+ +

This flexibility allows you to use function types as lightweight, dynamic implementations of interfaces, without the need for full struct definitions.

+ +

Application

+ +

One common use case for this pattern is testing. Instead of implementing a full mock, you can use an inline function to provide test specific behavior.

+
func TestHandler() {
+    mockDB := GetFn(func(key string) (string, error) {
+        if key == "foo" {
+            return "bar", nil
+        }
+        return "", fmt.Errorf("not found")
+    })
+
+    result, err := mockDB.Get("foo")
+    fmt.Println(result, err) // Outputs: bar, <nil>
+}
+
+

This approach is not limited to testing. It’s also useful for dependency injection, where you can pass in lightweight or context specific implementations of an interface.

+ +

This pattern is similar to how http.HandleFunc works. In the HTTP package, http.HandlerFunc is a function type that fulfills the http.Handler interface by implementing its ServeHTTP method. This allows functions to act as handlers, providing great flexibility in designing web servers.

+ + + +
+ + + + -- cgit v1.2.3