PHP转Go之基础数据类型的坑

本文主要讲解Go中基础数据类型,字符串、整数、浮点数、布尔这几个类型,像slice、map、struct等类型会有单独文章讲解

本文概要

  • 1、要转换思维,尽可能的不再定义弱类型,比如Go里的interface{}
  • 2、务必要注意强类型里的默认值

一、基础类型对比

我们在很多文章中都能看到类似的说明,这里copy一份,仅供参考

语言\类型 boolean string int float array
PHP bool string int float [1,2,3]/["a"=>1]
Go bool string int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64 float32、float64 slice/map

二、认知和使用差异点

  • 对于强类型语言只有类型相同的值才能够比较
php 复制代码
<?php
$a = 1;
$b = "1";
$c = true;
var_dump($a == $b);
var_dump($b == $c);
var_dump($a == $c);

// Output,当然php也支持强类型的判等比较 ===
bool(true)
bool(true)
bool(true)
go 复制代码
package main

import "fmt"

func main() {
	a := int32(1)
	b := int64(2)
	if a == b { // 这一行直接报错,根本无法编译过去
		fmt.Println("相等")
	}
}
  • 变量必须声明并初始化

在PHP中可以随时声明一个变量并赋予任意类型的任意值,这在Go中是行不通的,在强类型语言中,必须要提前声明变量类型,当然可以显示的声明,也可以是推导式的声明,并且Go中的所有类型都是有默认值的

go 复制代码
package main

import "fmt"

func main() {
	var a string // 默认空字符串
	var b int // 所有int都默认0
	var c float64 // 所有float64都默认0
	d := false // 推导出d是布尔值,bool值默认false
	fmt.Println(a, b, c, d)
   // b = "1" // 这种赋值会直接报错
}
// Output, 需注意string默认值为空字符串,所以未能有效输出展示
0 0 false

protobuf中也会利用默认值的特性,不传递变量是默认值的数据,减少传输数据量

  • 如何做类型转换

PHP中可以利用(int),(string)等方式直接完成类型强转,且不会报错,但是Go中就略显繁琐,不同的类型转到同一个类型可能使用的方法不同,比如:

go 复制代码
package main

import (
	"fmt"
	"strconv"
)

func main() {
	a := "1"
	b := 1.0
	var c interface{}
	c = "2"
	d, _ := strconv.Atoi(a)
	f, _ := strconv.Atoi(c.(string))
	fmt.Println(int(b)) // int和float之间可以直接转换,但是要注意范围溢出的问题
	fmt.Println(d, f)   // 字符串转数字需要使用特定函数,还要注意错误
   fmt.Printf("%d %.1f", bb, b) // 其他类型转字符串,使用格式化字符串函数,最简单直观
}

Go中使用类型转换最流行的一个库就是 spf13/cast 库了,强烈建议直接引用,不要自己造轮子,需要注意的是 cast 库避免了 panic,所以在很多转换过程中,对于失败的案例,返回值就变成了变量默认值,这个需要看下自己业务场景是否正常

  • Unicode字符处理

在php中,Unicode字符声明时并无特殊,而仅仅是在处理时,需要使用一些列以 mb_开头的函数

php 复制代码
<?php
$a = "我爱中国";
echo "字节长度:", strlen($a),"字符串长度:", mb_strlen($a);
// output: 字节长度:12字符串长度:4

而在Go中,Unicode对应的是一个类型 rune,而其各种操作函数跟之前没有区别 string 背后实际利用 []byte or []rune 实现,所以可以无缝互转

golang 复制代码
package main
import "fmt"
func main() {
	str := "我爱中国"
	fmt.Println("len", len(str), len([]rune(str)))
	fmt.Println(string([]rune(str)[1:])) // 如果这里不转为[]rune,则处理unicode字符时会出现乱码
}
// Output
len 12 4
爱中国

三、基础类型使用中的常见坑

  • json转换失败,引起异常

这里核心讲下类型引起的异常,其实强语言与js这种弱类型交互处理json坑真的很多

  1. "1" 和 1 是完全不同的类型,golang无法解析"1"为 1, 因类型不对应,直接报错
  2. {"key":null} 注意对于null,golang在解析时会解析成对应key声明的类型的默认值,而不一定是 nil
  3. 不要忽略 json.Unmarshal 的报错,某个字段无法解析报错时,可能会导致结构体内都是默认值,引起异常
  4. 使用 json.Unmarshal 或者 json.Marshal时,对于结构体中的小字字母开头的变量,处理时是忽略的,这个也可能会导致与预期不一致

json的处理值得写一篇单独文章来讲解,这里许个诺,稍后期待补充

  • float的精度问题

Golang中同样有浮点数精度问题的坑

golang 复制代码
package main

import (
	"fmt"
	"math/big"
)

func main() {
	f := 0.6
	ff := 0.7
	fmt.Println(f + ff)

	a, _ := new(big.Float).SetString("0.6")
	b, _ := new(big.Float).SetString("0.7")

	// 加法运算
	cccc := new(big.Float).Add(a, b)
	fmt.Println("Add:", cccc.String())
}
// Output
Add: 1.2999999999999998
Add: 1.3

可见对于高精度需求的计算时这还是有点问题的,Golang自带的math包可以有效的解决这个问题,另外推荐第三方库https://github.com/shopspring/decimal也能很好的解决这个问题,使用起来可能更方便一点~

下一章:讲解下 slicemap

相关推荐
是真的小外套22 分钟前
第十五章:XXE漏洞攻防与其他漏洞全解析
后端·计算机网络·php
ybwycx2 小时前
SpringBoot下获取resources目录下文件的常用方法
java·spring boot·后端
小陈工2 小时前
Python Web开发入门(十一):RESTful API设计原则与最佳实践——让你的API既优雅又好用
开发语言·前端·人工智能·后端·python·安全·restful
小阳哥AI工具2 小时前
Seedance 2.0使用真人参考图生成视频的方法
后端
IeE1QQ3GT2 小时前
使用ASP.NET Abstractions增强ASP.NET应用程序的可测试性
后端·asp.net
Full Stack Developme3 小时前
SpringBoot多线程池配置
spring boot·后端·firefox
sxhcwgcy5 小时前
SpringBoot 使用 spring.profiles.active 来区分不同环境配置
spring boot·后端·spring
稻草猫.7 小时前
Spring事务操作全解析
java·数据库·后端·spring
希望永不加班7 小时前
SpringBoot 整合 MongoDB
java·spring boot·后端·mongodb·spring
Lzh编程小栈8 小时前
数据结构与算法之队列深度解析:循环队列+C 语言硬核实现 + 面试考点全梳理
c语言·开发语言·汇编·数据结构·后端·算法·面试