Let me write it out front
Golang When building structures in , You need to create... Through optional parameters , How do we design a flexible API To initialize the structure .
Let's pass the following code snippet , Step by step, the flexibility based on the optional parameter mode is explained API How to design .
flexible API Create structure description
v1 edition
as follows Client It's a Client's sdk Structure , Yes host and port Two parameters , Our general usage is as follows :
package client
type Client struct {
host string
port int
}
// NewClient By passing parameters
func NewClient(host string, port int) *Client {
return &Client{
host: host,
port: port,
}
}
func (c *Client) Call() error {
// todo ...
return nil
}
We can see through host and port Two parameters can create a client Of sdk.
The code that is invoked is typically as follows :
package main import (
"client"
"log"
) func main() {
cli := client.NewClient("localhost", 1122)
if err := cli.Call(); err != nil {
log.Fatal(err)
}
}
And then one day ,sdk Made an upgrade , Several new parameters have been added , Such as timeout Timeout time ,maxConn maximum connection , retry Retry count ...
v2 edition
sdk Medium Client To define and create a structure API Change to the following :
package client
import "time"
type Client struct {
host string
port int
timeout time.Duration
maxConn int
retry int
}
// NewClient By passing parameters
func NewClient(host string, port int) *Client {
return &Client{
host: host,
port: port,
timeout: time.Second,
maxConn: 1,
retry: 0,
}
}
// NewClient adopt 3 Parameter creation
func NewClientWithTimeout(host string, port int, timeout time.Duration) *Client {
return &Client{
host: host,
port: port,
timeout: timeout,
maxConn: 1,
retry: 0,
}
}
// NewClient adopt 4 Parameter creation
func NewClientWithTimeoutAndMaxConn(host string, port int, timeout time.Duration, maxConn int) *Client {
return &Client{
host: host,
port: port,
timeout: timeout,
maxConn: maxConn,
retry: 0,
}
}
// NewClient adopt 5 Parameter creation
func NewClientWithTimeoutAndMaxConnAndRetry(host string, port int, timeout time.Duration, maxConn int, retry int) *Client {
return &Client{
host: host,
port: port,
timeout: timeout,
maxConn: maxConn,
retry: retry,
}
}
func (c *Client) Call() error {
// todo ...
return nil
}
Through the above creation API We found that creating Client All at once NewClientWithTimeout/NewClientWithTimeoutAndMaxConn/NewClientWithTimeoutAndMaxConnAndRetry...
We can see through host and port And other parameters can create a client Of sdk.
The code that is invoked is typically as follows :
package main import (
"client"
"log"
"time"
) func main() {
cli := client.NewClientWithTimeoutAndMaxConnAndRetry("localhost", 1122, time.Second, 1, 0)
if err := cli.Call(); err != nil {
log.Fatal(err)
}
}
This is the time , We found that v2 Version of API The definition is very unfriendly , The number of parameter combinations is also very large .
v3 edition
We need to refactor the parameters , Is it possible to merge configuration parameters into one structure ?
good , Let's put the parameters into Config in ,Client Define a cfg member
package client
import "time"
type Client struct {
cfg Config
}
type Config struct {
Host string
Port int
Timeout time.Duration
MaxConn int
Retry int
}
func NewClient(cfg Config) *Client {
return &Client{
cfg: cfg,
}
}
func (c *Client) Call() error {
// todo ...
return nil
}We can see that by defining Config Parameter can create a client Of sdk.
The code that is invoked is typically as follows :
package main import (
"client"
"log"
"time"
) func main() {
cli := client.NewClient(client.Config{
Host: "localhost",
Port: 1122,
Timeout: time.Second,
MaxConn: 1,
Retry: 0})
if err := cli.Call(); err != nil {
log.Fatal(err)
}
}
Here we find new problems ,Config All configured members should start with uppercase , It can only be used when it is open to the public , But as a sdk, We generally do not recommend exporting these members .
What should we do ?
v4 edition
We return to the original definition ,Client Or that one? Client, There are many configuration member variables , We use the optional parameter mode to sdk refactoring .
The code after refactoring is as follows
package client
import "time"
type Client struct {
host string
port int
timeout time.Duration
maxConn int
retry int
}
// Create... With optional parameters
func NewClient(opts ...func(client *Client)) *Client {
// Create an empty Client
cli := &Client{}
// Call the optional parameter functions one by one , Copy the parameters of each function configuration to cli in
for _, opt := range opts {
opt(cli)
}
return cli
}
// hold host Parameters , Pass to function parameters c *Client
func WithHost(host string) func(*Client) {
return func(c *Client) {
c.host = host
}
}
func WithPort(port int) func(*Client) {
return func(c *Client) {
c.port = port
}
}
func WithTimeout(timeout time.Duration) func(*Client) {
return func(c *Client) {
c.timeout = timeout
}
}
func WithMaxConn(maxConn int) func(*Client) {
return func(c *Client) {
c.maxConn = maxConn
}
}
func WithRetry(retry int) func(*Client) {
return func(c *Client) {
c.retry = retry
}
}
func (c *Client) Call() error {
// todo ...
return nil
}
We can choose parameters freely , Create a client Of sdk.
The code that is invoked is typically as follows :
package main import (
"client"
"log"
"time"
) func main() {
cli := client.NewClient(
client.WithHost("localhost"),
client.WithPort(1122),
client.WithMaxConn(1),
client.WithTimeout(time.Second))
if err := cli.Call(); err != nil {
log.Fatal(err)
}
}
From the code you call, you can see , our sdk The definition becomes flexible and beautiful .
Open source best practices
Finally, let's look at the best practice projects in this way .
gRpc
grpc.Dial(endpoint, opts...) // Dial creates a client connection to the given target.
func Dial(target string, opts ...DialOption) (*ClientConn, error) {
return DialContext(context.Background(), target, opts...)
} func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *ClientConn, err error) {
cc := &ClientConn{
target: target,
csMgr: &connectivityStateManager{},
conns: make(map[*addrConn]struct{}),
dopts: defaultDialOptions(),
blockingpicker: newPickerWrapper(),
czData: new(channelzData),
firstResolveEvent: grpcsync.NewEvent(),
} for _, opt := range opts {
opt.apply(&cc.dopts)
}
// ...
}
End .
Have fun ~
【Golang】 When creating a structure with configuration parameters , How optional parameters should be transferred ? More articles about
- 【C++】 Structure / Array of structs / Structure pointer / Nested structure / Function parameter /const
One . Structure declaration struct Student { // Member list string name; int age; int score; }; //s3; Directly declare when defining int main() { struct ...
- go The structure of language foundation makes function parameters Value passing and address passing
1. The struct transfers function parameter values Example : package main // There must be a main package import "fmt" // Define a structure type type Student struct { ...
- go The language structure is used as a function parameter , We use value passing
After verification ,go The language structure is used as a function parameter , We use value passing . Therefore, for large-scale structural body transfer parameters , Considering the performance loss of value transfer , It is better to use pointer transfer . Verification code : package main import ( "fmt& ...
- In depth understanding of C Language - Structure is used as function parameter
Structure is used as function parameter , stay C Language is a common phenomenon , In this case, for the sake of memory , Non transitive structure , Instead, you pass the address of the structure Structure definition struct Man { char name[64]; int age; }; The structure can be connected with ...
- Use class / Structure is about ZeroMomery Wrong usage
Today, my colleague wrote the following structure : typedef struct _tagInfo { std::list<int> lst; std::vector<int> nVec; } INF ...
- use set、map When storing user-defined structures, such as, the precautions for judging whether each element is the same inside the container
STL As a general template, it greatly facilitates C++ User programming , Because it can store elements of any data type If we want to use it set And map To store custom structures , as follows struct pp { double xx; double y ...
- C# Parameters and calling methods in ( Optional parameters 、 Named parameters 、 Nullable parameter )
Named parameters and Optional parameters yes C# framework 4.0 New features come out . One . General method definition and call public void Demo1(string x, int y) { //do someth ...
- golang The structure in is copied as a function parameter or function return value
1. When a struct is used as a parameter or return value of a function , Will be copied again if you don't want to copy , Structure pointers can be passed package main import "fmt" type Person struct { ...
- WPF in ItemsControl Bound to the Google ProtocolBuffer The performance of the structure of
background : Recently I met a DataGrid Performance problems of : There's probably something in it 4000 Data , The binding of ItemSource Class has only one layer of data , It's simple List( Each of them is Protocol Buffer A class generated automatically ,1 ...
- c The structs in a language are value types , When one structure is assigned to another , Pass... For value
#include <stdio.h> int main() { struct person { int age; }; }; // Value passed , take p1 The values of all member variables in the p2 The corresponding member variable in ...
Random recommendation
- Qt Implement port scanner
First of all, let's show the effect : Interface by Qt The designer made it . There are two main categories . First, the main function : #include "mainwindow.h" #include <QApplication& ...
- Remember a Url rewrite _ After the release iis 404
hold api The package is finished , Customer requirements app Of url Can we not change ( The customer used it before php Of api Development app, A lot has been developed , So I hope it doesn't change url). But the rule is :xx/api.php?s=/{controller ...
- 20151221jquery Learning notes -- Validation plug-ins
Validation plug-ins (validate.js), It is a plug-in to verify the validity of regular form data . Use it , It greatly liberates the complicated verification process on the form , And the improvement of the error prompt display also increases the user experience . One . Use validate.js Plug in website ...
- use max_dump_file_size Parameter limits trc file size
max_dump_file_size Parameters : This parameter can limit the corresponding process trc file size ( Is the process oracle Corresponding to the background and foreground applications server process) Use cases : If it's one trc The document has 4 ...
- How to use it? snapman A person develops a complex software development project management system in three days
snapman It's a simple and powerful team collaboration software , The information above can be data . It can be rules . It can also be automation code : Most importantly, it's a collaborative platform that can be developed , All information can be applied to all people or machines , Greatly reduced the complexity of the work . soft ...
- Java Unit tests JUnit piece
Unit testing is writing test code , Should be accurate . Quickly ensure the correctness of basic program modules . Good unit testing standards JUnit yes Java Unit test framework , Already in Eclipse Default installation in . JUnit4 JUnit4 To recognize by means of annotations ...
- iOS.Animations.by.Tutorials.v2.0 Sinicization ( Four )
The third chapter transformation In the previous two chapters , You learned how to create views based on position and transparency alpha Animation properties of the animation . however , If you want to add animation to the view or delete animation , How will you handle it ? You can use the methods in the previous chapters to set the animation effect of the interface ...
- 17-Flink consumption Kafka write in Mysql
Stamp more articles : 1-Flink introduction 2- Local environment construction & Build the first Flink application 3-DataSet API 4-DataSteam API 5- Cluster deployment 6- Distributed cache 7- Restart strategy 8-Fli ...
- selenium perform JavaScript sentence : Control the scroll bar Focusing on the element Change the drop-down options
1. perform js Script Control the scroll bar # http://www.cnblogs.com/yoyoketang/p/6128655.html In [347]: js = "window.scrol ...
- [ Re posting ]pfSense The use of soft routing system
The illustration pfSense The use of soft routing system (NAT function ) http://seanlook.com/2015/04/23/pfsense-usage/ Published in 2015-04-23 | Updated on : 2015- ...
![buuctf [PHP]inclusion](/img/02/d328ed84e4641c09c5b1eba3ac6ea9.png)



![[FAQ] summary of common problems and solutions during the use of rest API interface of sports health service](/img/73/c6c4c0d92e5adb2e831ea4a0290ee9.jpg)
![[NLP] NLP full path learning recommendation](/img/d8/a367c26b51d9dbaf53bf4fe2a13917.png)
![[deep learning] the credit card fraud anomaly detection based on the deep learning autoencoder is very effective](/img/69/505707755e6b003d90cdb07e61914a.jpg)

