分类 Golang 下的文章

4种资源:

资源拥有者(小明);
客户端(软文系统);
授权服务(微信公众号平台);
受保护资源(小明公众号内的文章);

auth2.0.png

QQ20231122-234339@2x.png

QQ20231123-000141@2x.png

注意三点:

1、交叉编译,要把我的 go 代码编译为 window 执行的文件
2、编译 html 等静态文件到 exe 文件中
3、启动 window 的浏览器

package main
import (
    _ "embed"
    "log"
    "net"
    "net/http"

    "github.com/gin-gonic/gin"
    "github.com/skratchdot/open-golang/open"
)
// 这里不能有空格
//go:embed templates/transaction.html
var content []byte

func main() {
    l, err := net.Listen("tcp", "localhost:3000")
    if err != nil {
        log.Fatal(err)
    }
    r := SetRouter()

    // 使用第三方的包打开chrome
    open.RunWith("http://localhost:3000/transaction", "chrome")
    // Start the blocking server loop
    http.Serve(l, r)
}

func SetRouter() *gin.Engine {
    r := gin.Default()
    // 显示发起交易页面
    r.GET("/transaction", func(c *gin.Context) {
        c.Data(http.StatusOK, "text/html", content)
    })
    return r
}

交叉编译

Linux 下编译 Mac 和 Windows 64 位可执行程序

CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go

Mac 下编译 Linux 和 Windows 64 位可执行程序

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go

Windows 下编译,依次执行如下命令

SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build -o goblog

通过如下命令可查看 Go 支持 OS 和平台列表:

go tool dist list
aix/ppc64
android/386
android/amd64
android/arm
android/arm64
darwin/amd64
darwin/arm64
dragonfly/amd64
freebsd/386
freebsd/amd64
freebsd/arm
freebsd/arm64
illumos/amd64
ios/amd64
ios/arm64
js/wasm
linux/386
linux/amd64
linux/arm
linux/arm64
linux/mips
linux/mips64
.
.
.
windows/386
windows/amd64
windows/arm
windows/arm64

参考编辑:https://learnku.com/articles/70273?#reply275739

本人 MacOS系统如下所示:
QQ20230822-093612@2x.png

按照Wails安装步骤时,出现“zsh: command not found: wails”的问题,于是Goolge搜索并找到如下的解决方案:

https://github.com/wailsapp/wails/issues/2046

解决办法在https://github.com/wailsapp/wails/issues/2046#issuecomment-1376535844

On my MacOs Ventura:
Installed go => it is installed to "/usr/local/go"
Installed wails => it is installed in "~go/bin/wails"
Result: "zsh: command not found: wails"
QuickFix for me: sudo cp ~/go/bin/wails /usr/local/go/bin/

其实就这一句话:sudo cp ~/go/bin/wails /usr/local/go/bin/

Fyne一款golang的桌面,对中文支持不够友好,解决办法:
1、环境变量FYNE_FONT=ttf文件路径。
2、代码设置环境变量,如下:

func init(){
    os.Setenv("FYNE_FONT","./yahei.ttf")
}

注意,上面两种办法任一种都可以。

const (
    MININT64 = -922337203685477580
    MAXINT64 = 9223372036854775807
)
 
 
func Max(nums... int64) int64 {
    var maxNum int64 = MININT64
    for _, num := range nums {
        if num > maxNum {
            maxNum = num
        }
    }
    return maxNum
}
 
 
 
 
func Min(nums... int64) int64 {
    var minNum int64 = MAXINT64
    for _, num := range nums {
        if num < minNum {
            minNum = num
        }
    }
    return minNum 
}
 
 
 
func Sum(nums... int64) int64 {
    var sumNum int64 = 0
    for _, num := range nums {
            sumNum += num
    }
    return sumNum 
}

以上是对整形的实现,浮点型需要使用math.Max包下的函数更为科学严谨。

package main

import (
    "context"
    "github.com/wechatpay-apiv3/wechatpay-go/core"
    "github.com/wechatpay-apiv3/wechatpay-go/core/option"
    "github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
    "github.com/wechatpay-apiv3/wechatpay-go/utils"
    "log"
    "time"
)

func main() {

    var (
        mchID                      string = "xxxx"                               // 商户号
        mchCertificateSerialNumber string = "xxxxx" // 商户证书序列号
        mchAPIv3Key                string = "xxxxxx"         // 商户APIv3密钥
    )

    // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
    mchPrivateKey, err := utils.LoadPrivateKeyWithPath("./apiclient_key.pem")
    if err != nil {
        log.Fatal("load merchant private key error")
    }

    ctx := context.Background()
    // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力
    opts := []core.ClientOption{
        option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
    }
    client, err := core.NewClient(ctx, opts...)
    if err != nil {
        log.Printf("new wechat pay client err:%s", err)
    }

    svc := native.NativeApiService{Client: client}
    resp, result, err := svc.Prepay(ctx,
        native.PrepayRequest{
            Appid:       core.String("xxxxxxx"),
            Mchid:       core.String("1650242918"),
            Description: core.String("Image形象店-深圳腾大-QQ公仔"),
            OutTradeNo:  core.String("1217752501201407033233368018"),
            TimeExpire:  core.Time(time.Now()),
            Attach:      core.String("自定义数据说明"),
            NotifyUrl:   core.String("https://www.weixin.qq.com/wxpay/pay.php"),
            GoodsTag:    core.String("WXG"),
            //LimitPay:      []string{"LimitPay_example"},
            SupportFapiao: core.Bool(false),
            Amount: &native.Amount{
                Currency: core.String("CNY"),
                Total:    core.Int64(1),
            },
            Detail: &native.Detail{
                CostPrice: core.Int64(608800),
                GoodsDetail: []native.GoodsDetail{native.GoodsDetail{
                    GoodsName:        core.String("iPhoneX 256G"),
                    MerchantGoodsId:  core.String("ABC"),
                    Quantity:         core.Int64(1),
                    UnitPrice:        core.Int64(828800),
                    WechatpayGoodsId: core.String("1001"),
                }},
                InvoiceId: core.String("wx123"),
            },
            SettleInfo: &native.SettleInfo{
                ProfitSharing: core.Bool(false),
            },
            SceneInfo: &native.SceneInfo{
                DeviceId:      core.String("013467007045764"),
                PayerClientIp: core.String("14.23.150.211"),
                StoreInfo: &native.StoreInfo{
                    Address:  core.String("广东省深圳市南山区科技中一道10000号"),
                    AreaCode: core.String("440305"),
                    Id:       core.String("0001"),
                    Name:     core.String("腾讯大厦分店"),
                },
            },
        },
    )

    if err != nil {
        log.Println("\n用我了")
        // 处理错误
        log.Printf("call Prepay err:%s", err)
    } else {
        log.Println("\n正确的结果为:")
        // 处理返回结果
        log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
    }
}

注意修改商户相关参数。

func BytesToString(b []byte) (s string) {
    _bptr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
    _sptr := (*reflect.StringHeader)(unsafe.Pointer(&s))
    _sptr.Data = _bptr.Data
    _sptr.Len = _bptr.Len
    return s
}

// 随机生成字符串
func RandomString(l int) string {
    str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
    bytes := []byte(str)
    var result []byte = make([]byte, 0, l)
    r := rand.New(rand.NewSource(time.Now().UnixNano()))
    for i := 0; i < l; i++ {
        result = append(result, bytes[r.Intn(len(bytes))])
    }
    return BytesToString(result)
}

func main() {
    fmt.Println(RandomString(64))
}

package main

import (
    "log"
)

type Notifier interface {
    Notify() error
}

type User struct {
    Name  string
    Email string
}

func (u *User) Notify() error {
    log.Printf("User: Sending user Email To %s<%s>", u.Name, u.Email)
    return nil
}

func SendNotification(notify Notifier) error {
    return notify.Notify()
}

func main() {
    user := User{
        Name:  "liziyu",
        Email: "13073932@163.com",
    }
    //user.Notify()
    SendNotification(user)
    //cannot use user (variable of type User) as Notifier value in argument to SendNotification: User does not implement Notifier (method Notify has pointer receiver)
}

cannot use user (variable of type User) as Notifier value in argument
to SendNotification: User does not implement Notifier (method Notify
has pointer receiver)

原因:

上面的错误说明Notify方法的接受者是指针类型的,因此User类型的值并没有实现该方法,也就是没有实现Notifier接口,不能作为参数传入。

为什么编译器不认为值类型实现了接口呢?确定接口是否被实现的规则是基于这些方法的接收者以及如何进行接口调用。下面是关于编译器如何确定类型的值或指针是否实现接口的规则:

指针类型(T)的方法集包含接受者是值类型(T)和指针类型(T)的方法。

该规则表明,如果用于调用接口方法的变量是指针,那么不管方法的接受者是值类型还是指针类型都可以被调用。此规则不适用于我们的示例,因为我们向SendNotification函数传递一个值不是指针。

值类型(T)的方法集只包含所有接受者为值类型(T)的方法

该规则表明,如果我们用于调用接口的变量是值类型,那么只有接收者也是值类型的方法才能满足接口。此规则不适用于我们的示例,因为Notify方法的接收者是一个指针。

换句话说:

接收者为值类型(T)的方法集不包含接收者为指针类型(*T)的方法。

这就是我们的前面代码报错的情况。Notify方法的接收者是指针,我们使用值进行接口方法调用会报错。要解决这个问题,我们只需要将User值的地址传递给SendNotification函数即可:
func main() {
    user := &User{
        Name:  "liziyu",
        Email: "13073932@163.com",
    }

    SendNotification(user)
}

// Output:
User: Sending User Email To liziyu<13073932@163.com>



最后用两句不太严谨的话总结一下:

1、当类型(结构体或标准类型)对象为“值类型”时,该对象只能调用它的接受者为“值类型”的接口方法。
2、当类型(结构体或标准类型)对象为“指针类型”时,该对象不但能调用它的接受者为“值类型”的接口方法,还能调用接受者为“指针类型”的接口方法。

->>>>>>>>>>>>>>>>>>>>>>以下代码有同工异曲之妙<<<<<<<<<<<<<<<<<<-

type F interface {
  f()
}

type S1 struct{}

func (s S1) f() {}

type S2 struct{}

func (s *S2) f() {}

s1Val := S1{}
s1Ptr := &S1{}
s2Val := S2{}
s2Ptr := &S2{}

var i F
i = s1Val
i = s1Ptr
i = s2Ptr

//  下面代码无法通过编译。因为 s2Val 是一个值,而 S2 的 f 方法中没有使用值接收器
//   i = s2Val
//   i.f() 报错 :cannot use s2Val (variable of type S2) as F value in assignment: S2 does not implement F (method f has pointer receiver)

QQ20230625-113225@2x.png

链接:https://www.jianshu.com/p/59a73d426e59

1、new (T) 为每个新的类型 T 分配一片内存,初始化为零值,并且返回类型为 * T 的内存地址,这种方法返回一个指向类型为 T,值为 0 的地址的指针,它适用于值类型如数组和结构体;它相当于 &T{}。

2、make(T) 返回一个类型为 T 的初始值,它只适用于 3 种内建的引用类型:slice、map 和 channel类型。

new () 是一个函数,不要忘记它的括号

15个协程

package main

import (
    "fmt"
)

func inputNum(inChan chan int, n int) {
    for i := 1; i <= n; i++ {
        inChan <- i
    }
    fmt.Println("inChan 写入完成")
    close(inChan)
}

func countNum(inChan chan int, primeChan chan int, exitChan chan bool) {
    for {
        //time.Sleep(time.Millisecond * 10)
        num, ok := <-inChan
        if !ok {
            break
        }
        flag := true
        for i := 2; i < num; i++ {
            if num%i == 0 {
                flag = false
                break
            }
        }
        if flag {
            primeChan <- num
        }
    }
    fmt.Println("有一个countNum被关闭了")
    exitChan <- true
}

func main() {

    inChan := make(chan int, 1000)
    primeChan := make(chan int, 1000)
    exitChan := make(chan bool, 15)

    go inputNum(inChan, 80000)

    for i := 0; i < 15; i++ {
        go countNum(inChan, primeChan, exitChan)
    }

    go func() {
        for i := 0; i < 4; i++ {
            <-exitChan
        }
        close(primeChan)
    }()

    for {
        v, ok := <-primeChan
        if !ok {
            break
        }
        fmt.Println(v)
    }
}