Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

空值检查和非 string 值 的 toString() #6

Closed
wants to merge 1 commit into from

Conversation

morlay
Copy link
Contributor

@morlay morlay commented Dec 21, 2017

Request 的参数还是应该保留对应的类型,以方便用户赋值,全 string 太过暴力

@gaort
Copy link

gaort commented Dec 22, 2017

@morlay
感谢您的贡献

  1. SDK实际上发出的是http请求,不论用户之前填入的参数类型为哪种,最终根据参数位置不同,发出的都会是string(query&path)和[]byte(content)
  2. 目前阿里云所有请求中,支持的叶子端参数类型只有string/int32/int64/float64/bool 五种,这五种类型都是可以直接toString()的

@gaort gaort closed this Dec 22, 2017
@morlay
Copy link
Contributor Author

morlay commented Dec 22, 2017

@gaort
Go lang 不是 Java,int 等并没有这样的用法 2.toString() 以转换为 string,而是需要利用 fmt.Sprintf("%v", 2) 或者 strconv.FormatInt(2, 10) 予以转换。

现在 Request 参数类型均声明为 string, 当用户需要用如下的方式使用。

type XXXRequest struct {
   PageNumber string `position:"Query" name:"PageNumber"`
}

func main() {
   req :=  XXXRequest{
      PageNumber: fmt.Sprintf("%v", 2),
  }
}

而用户方更希望是这样的方式

type XXXRequest struct {
   PageNumber int32 `position:"Query" name:"PageNumber"`
}

func main() {
   req :=  XXXRequest{
      PageNumber: 2,
  }
}

但当定义为后者时,当前 Query 的拼接处理逻辑是有问题。这里需要更新逻辑,去做 toString 的转换。
这涉及两个问题,

第一,reflect.Value.String(), 除了 string 外,如此使用是无法得到对应 type 的 string 化的值的,详见 https://play.golang.org/p/nIeeiaWQ_sg

package main

import (
	"fmt"
	"reflect"
)

func main() {
	fmt.Println(reflect.ValueOf("").String()) 
	fmt.Println(reflect.ValueOf(1).String()) // <int Value>
	fmt.Println(reflect.ValueOf(int64(1)).String()) // <int64 Value>
	fmt.Println(reflect.ValueOf(1.1).String()) // <float64 Value>
	fmt.Println(reflect.ValueOf(true).String()) // <bool Value>
}

那意味着,当前逻辑中,Query 拼接得不到预期结果,哪怕是该值未赋值(这里参看问题二),
因为我们需要根据数据类型进行 string 化。

问题二, 0 值问题 https://tour.golang.org/basics/12
在 Golang 中,不同的类型是有 0 值的,这意味着,我们需要判断该值是否为 0 值,再决定是否要拼接到为 Query 上,否则, 0 值为带到 Query 上出现 PageNumber=0,影响接口调用。
另外,这里有个特殊情况,bool,因为 0 值为 false,没办法判定是否赋值的,因此 bool 类型的参数需要保留为 string(或者用一个特殊的 enum 类型进行代理)。

这就是为了让 Request Type 使用更方便需要背后做的处理。也是该 PR 做的事。

也可以参考社区已有实现,https://github.com/denverdino/aliyungo/blob/master/util/encoding.go#L46

@gaort
Copy link

gaort commented Dec 22, 2017

@morlay 感谢您的贡献
1.是这样的,目前生成的request的确存在将很多原本不是string类型的字段生成为string类型的问题
这个bug已经在生成器中改造完成,预计下周会和很多bugfix以及功能更新一起发布为1.0版(因为无法向下兼容)

  1. 0值这块,的确存在不好判断的问题,您提到的enum可以解决bool的false问题,但是int为0并不能代表“空值”:我们无法排除用户给int参数赋值为0的场景。目前我们仍在讨论完美的解决方案,也欢迎您一起参与其中

@morlay
Copy link
Contributor Author

morlay commented Dec 22, 2017

@gaort

1、如果生成为带类型的,刚才提到的转换逻辑不修改,就会出现我刚才提到的问题。
2、对于大部分场景,0 就是空,如果确实有例外,可以参考标准库 database/sql.NullInt64 (https://golang.org/pkg/database/sql/#NullInt64) 的做法。

@morlay
Copy link
Contributor Author

morlay commented Dec 22, 2017

比如这样,

func Int64(i int64) MyInt64 {
	return MyInt64{
		Int64: i,
		Valid: true,
	}
}

type MyInt64 struct {
	Int64 int64
	Valid bool
}

func (v MyInt64) String() string {
	if v.Valid {
		return fmt.Sprintf("%d", v.Int64)
	}
	return ""
}

String() string 是通用 interface,PR 中已有逻辑 cover。

@morlay
Copy link
Contributor Author

morlay commented Dec 22, 2017

或者,https://github.com/google/go-github/issues/19,指针化以区分 unset 和 zero value

还有一种是给 baseRequest 加个白名单, 当 0 值的时候也可拼接到 Query 上

比如

type baseRequest struct {
    zeroFields  []string
}

func (br *baseRequest) WithZeroFields(fieldNames ...string) {
    br.zeroFields = append(br.zeroFields, zeroFields...)
}

@morlay morlay mentioned this pull request Dec 26, 2017
@gaort
Copy link

gaort commented Dec 26, 2017

@morlay 感谢您的贡献,因为这几种方式都会对用户接口产生影响,请容许我们内部一起讨论下,谢谢

@gaort
Copy link

gaort commented Dec 26, 2017

@morlay 已经在 #14 中修复

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants