Golang中if条件语句的工作原理解析
Golang中if条件语句的工作原理解析
我正在尝试为IBM(db2)数据库开发一个Go驱动程序。
对于Windows,API定义如下:
(我将加载dll并使用函数)
func SQLColAttribute(statementHandle SQLHSTMT, ColumnNumber SQLUSMALLINT, FieldIdentifier SQLUSMALLINT, CharacterAttributePtr SQLPOINTER, BufferLength SQLSMALLINT, StringLengthPtr *SQLSMALLINT, NumericAttributePtr *SQLLEN) (ret SQLRETURN) {
r0, _, _ := syscall.Syscall9(procSQLColAttribute.Addr(), 7, uintptr(statementHandle), uintptr(ColumnNumber), uintptr(FieldIdentifier), uintptr(CharacterAttributePtr), uintptr(BufferLength), uintptr(unsafe.Pointer(StringLengthPtr)), uintptr(unsafe.Pointer(NumericAttributePtr)), 0, 0)
ret = SQLRETURN(r0)
return
}
对于其他平台,定义如下:
(使用cgo,意味着我将包含sqlcli.h文件,然后导入C)
func SQLColAttribute(statementHandle SQLHSTMT, ColumnNumber SQLUSMALLINT, FieldIdentifier SQLUSMALLINT, CharacterAttributePtr SQLPOINTER, BufferLength SQLSMALLINT, StringLengthPtr *SQLSMALLINT, NumericAttributePtr SQLPOINTER) (ret SQLRETURN) {
r := C.SQLColAttribute(C.SQLHSTMT(statementHandle),C.SQLUSMALLINT(ColumnNumber),C.SQLUSMALLINT(FieldIdentifier),C.SQLPOINTER(CharacterAttributePtr),C.SQLSMALLINT(BufferLength),(*C.SQLSMALLINT)(StringLengthPtr),(C.SQLPOINTER)(NumericAttributePtr))
return SQLRETURN(r)
}
我使用这些函数的代码:
func (r *Rows) ColumnTypeLength(index int) (length int64, ok bool) {
if runtime.GOOS == "windows" {
ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH, api.SQLPOINTER(unsafe.Pointer(nil)), 0, (*api.SQLSMALLINT)(nil), (*api.SQLLEN)(&length))
if IsError(ret) {
fmt.Println(ret)
return 0, false
}
return length, true
} else {
ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH, api.SQLPOINTER(unsafe.Pointer(nil)), 0, (*api.SQLSMALLINT)(nil), api.SQLPOINTER(unsafe.Pointer(&length)))
if IsError(ret) {
fmt.Println(ret)
return 0, false
}
return length, true
}
}
错误:
当我在Windows上运行代码时,出现以下错误:
# github.com/ibmdb/go_ibm_db
C:\Users\rakhil\go\src\github.com\ibmdb\go_ibm_db\rows.go:55:165: cannot use api.SQLPOINTER(unsafe.Pointer(&length)) (type api.SQLPOINTER) as type *api.SQLLEN in argument to api.SQLColAttribute
当我在Linux上运行代码时,出现以下错误:
cannot convert &length (type *int64) to type *api.SQLLEN
为什么Go在编译代码时不检查if条件?或者是否有其他方法可以运行这段代码?
谢谢。
更多关于Golang中if条件语句的工作原理解析的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我不确定该怎么做。
rows.go 中的第55行是哪一行?
不客气。
是的。我的程序将在哪里运行。
下一页 →
哪个操作系统?你编译时使用的那个吗?
如何处理这个问题?因为我无法编写两个函数,因为声明在 sql 包(database/sql)中。
编译应用程序的操作系统不一定就是运行该应用程序的操作系统。那么哪个是:
- A:编译应用程序时使用的操作系统
- B:运行已编译应用程序的操作系统
所以你的问题是为什么这个
if runtime.GOOS == "windows"
在Windows系统下不成立?
@NobbZ 能帮我处理这个问题吗。
谢谢
顺便问一下,你查看过 DB2 驱动列表 吗?
akhilravuri:
它同时执行了 if 和 else 代码
这是不可能的,if/else 绝不会同时执行。
它们都不会支持 SQLColAttribute API。 github.com/ibmdb/go_ibm_db 是我们的项目,我们正在尝试支持该 API,但遇到了此类错误。
我的问题是
在SQLColAttribute函数中,最后一个参数(NumericAttributePtr)在Windows上是SQLLEN类型,而在其他平台上是SQLPOINTER类型。 因此,我使用了if条件来处理这种情况,但它同时执行了if和else的代码并产生了错误。
第55行
ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH, api.SQLPOINTER(unsafe.Pointer(nil)), 0, (*api.SQLSMALLINT)(nil), api.SQLPOINTER(unsafe.Pointer(&length)))
if 和 runtime.GOOS 的使用符合预期:
package main
import (
"fmt"
"runtime"
)
func main() {
if runtime.GOOS == "linux" {
fmt.Println("This is Linux: " + runtime.GOOS)
} else {
fmt.Println("This is not Linux: " + runtime.GOOS)
}
}
假设这是 rows.go 文件:
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package go_ibm_db
import (
"database/sql/driver"
"fmt"
"io"
"reflect"
"unsafe"
"github.com/ibmdb/go_ibm_db/api"
)
type Rows struct {
os *ODBCStmt
}
func (r *Rows) Columns() []string {
names := make([]string, len(r.os.Cols))
for i := 0; i < len(names); i++ {
names[i] = r.os.Cols[i].Name()
}
return names
}
func (r *Rows) ColumnTypeLength(index int) (length int64, ok bool) {
if runtime.GOOS == "windows" {
ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH, api.SQLPOINTER(unsafe.Pointer(nil)), 0, (*api.SQLSMALLINT)(nil), (*api.SQLLEN)(&length)))
if IsError(ret) {
fmt.Println(ret)
return 0, false
}
return length, true
} else {
ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH, api.SQLPOINTER(unsafe.Pointer(nil)), 0, (*api.SQLSMALLINT)(nil), api.SQLPOINTER(unsafe.Pointer(&length)))
if IsError(ret) {
fmt.Println(ret)
return 0, false
}
return length, true
}
}
func (r *Rows) Next(dest []driver.Value) error {
ret := api.SQLFetch(r.os.h)
if ret == api.SQL_NO_DATA {
return io.EOF
}
if IsError(ret) {
return NewError("SQLFetch", r.os.h)
}
for i := range dest {
v, err := r.os.Cols[i].Value(r.os.h, i)
if err != nil {
return err
}
dest[i] = v
}
return nil
}
func (r *Rows) Close() error {
return r.os.closeByRows()
}
问题出在类型不匹配上,而不是if条件语句的工作原理。Go编译器在编译时会检查所有代码路径的类型一致性,即使某些路径在特定平台上不会执行。
在Windows版本中,NumericAttributePtr参数类型是*SQLLEN,但在你的调用中传递的是api.SQLPOINTER(unsafe.Pointer(&length)),这是一个SQLPOINTER类型,不是*SQLLEN。
在Linux版本中,NumericAttributePtr参数类型是SQLPOINTER,但&length是*int64类型,不能直接转换为*api.SQLLEN。
解决方案是使用类型转换和unsafe.Pointer来确保类型匹配:
func (r *Rows) ColumnTypeLength(index int) (length int64, ok bool) {
if runtime.GOOS == "windows" {
var sqllen api.SQLLEN
ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH,
api.SQLPOINTER(unsafe.Pointer(nil)), 0,
(*api.SQLSMALLINT)(nil),
&sqllen)
if IsError(ret) {
fmt.Println(ret)
return 0, false
}
length = int64(sqllen)
return length, true
} else {
var sqllen api.SQLLEN
ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH,
api.SQLPOINTER(unsafe.Pointer(nil)), 0,
(*api.SQLSMALLINT)(nil),
api.SQLPOINTER(unsafe.Pointer(&sqllen)))
if IsError(ret) {
fmt.Println(ret)
return 0, false
}
length = int64(sqllen)
return length, true
}
}
或者使用更简洁的版本:
func (r *Rows) ColumnTypeLength(index int) (length int64, ok bool) {
var sqllen api.SQLLEN
if runtime.GOOS == "windows" {
ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH,
api.SQLPOINTER(unsafe.Pointer(nil)), 0,
(*api.SQLSMALLINT)(nil),
&sqllen)
if IsError(ret) {
fmt.Println(ret)
return 0, false
}
} else {
ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH,
api.SQLPOINTER(unsafe.Pointer(nil)), 0,
(*api.SQLSMALLINT)(nil),
api.SQLPOINTER(unsafe.Pointer(&sqllen)))
if IsError(ret) {
fmt.Println(ret)
return 0, false
}
}
length = int64(sqllen)
return length, true
}
这样处理确保了类型匹配,同时保持了跨平台的兼容性。


