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

21 回复

选项A

更多关于Golang中if条件语句的工作原理解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我不确定该怎么做。

rows.go 中的第55行是哪一行?

不客气。

是的。我的程序将在哪里运行。

下一页 →

哪个操作系统?你编译时使用的那个吗?

有没有办法在编译时检测操作系统 @lutzhorn
因为 runtime.GOOS 是在运行时检测的。

如何处理这个问题?因为我无法编写两个函数,因为声明在 sql 包(database/sql)中。

编译应用程序的操作系统不一定就是运行该应用程序的操作系统。那么哪个是:

  • A:编译应用程序时使用的操作系统
  • B:运行已编译应用程序的操作系统

所以你的问题是为什么这个

if runtime.GOOS == "windows"

在Windows系统下不成立?

@NobbZ 能帮我处理这个问题吗。

谢谢

对于普通文件它运行得很好,但到了那个 rows.go 文件时,它的运行就变得很奇怪了。

顺便问一下,你查看过 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)))

ifruntime.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)
	}
}

参见 https://play.golang.org/p/wVdvlIf4-ON

假设这是 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
}

这样处理确保了类型匹配,同时保持了跨平台的兼容性。

回到顶部