Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
DCloud
unidocs-uni-app-x-zh
提交
ae099ee8
U
unidocs-uni-app-x-zh
项目概览
DCloud
/
unidocs-uni-app-x-zh
通知
144
Star
2
Fork
33
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
9
列表
看板
标记
里程碑
合并请求
11
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
unidocs-uni-app-x-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
9
Issue
9
列表
看板
标记
里程碑
合并请求
11
合并请求
11
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
ae099ee8
编写于
11月 12, 2024
作者:
WOSHIMAHAIFENG
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Update data-type.md
上级
8c777f13
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
211 addition
and
120 deletion
+211
-120
docs/uts/data-type.md
docs/uts/data-type.md
+211
-120
未找到文件。
docs/uts/data-type.md
浏览文件 @
ae099ee8
```
```
# 类型@data-type
强类型语言的特点,是数据类型要求严格。它带来2个好处:
1.
高性能:明确的类型有更大的优化空间,在Android等OS上可以节省内存、提高运算速度;web端由于仍编译为js,不具有类型性能优化。
2.
安全的代码:强类型代码编写虽然没有弱类型自由,但类型检查、非空检查...等各种检查可以提高代码的健壮性。
...
...
@@ -11,6 +16,7 @@
比如
`"abc"`
和
`"你好"`
,都属于字符串string,所有string类型有相同的方法、属性,比如
`.length`
属性获取字符串长度。
UTS 的类型有:
-
基础类型:boolean、number、string、any、null,都是小写。前3个typeof返回类型名称,null的typeof是object,any的typeof是运行时值的类型。
-
对象类型:Date、Array、Map、Set、UTSJSONObject,首字母大写。typeof返回"object",判断准确类型需使用 instanceof
-
使用 type 来自定义类型
...
...
@@ -23,7 +29,6 @@ UTS 的类型有:
除了上述
`运行时类型`
,uts还有
`开发时类型`
的概念,指为了在开发期间ide可以更好的进行代码提示和校验,但在编译后这些类型会被擦除,变成
`运行时类型`
。详见
[
开发时类型
](
#devtype
)
和
[
类型擦除
](
#type-erasure
)
## 布尔值(boolean)
布尔是简单的基础类型,只有2个值:
`true`
和
`false`
。
...
...
@@ -36,6 +41,7 @@ c = true // 后续为变量赋值字面量
```
**注意:**
-
在js里,true == 1、 false == 0。但在其他强类型语言里,
`1`
和
`0`
是数字类型,无法和布尔类型相比较。
-
注意 boolean 不要简写成 bool
...
...
@@ -68,6 +74,7 @@ let d = 3.14159 //注意:目前版本推导d为float类型,新版本
请注意:
number本身的使用很简单,但混入了平台专有数字类型后,会引出很多细节需要学习。
-
如果您不调用原生API,初学uts时建议跳过本节,直接往下看string类型。
-
如果您是插件作者,那请务必仔细阅读本章节。
...
...
@@ -92,7 +99,6 @@ number本身的使用很简单,但混入了平台专有数字类型后,会
如果涉及大量运算,建议开发者不要使用 number、Int? ,要明确使用 Int等类型
[
详情
](
https://kotlinlang.org/docs/numbers.html#numbers-representation-on-the-jvm
)
#### Swift 专有的数字类型 @swiftnumber
|类型名称 |长度 |最小值 |最大值 |描述|
...
...
@@ -115,8 +121,8 @@ number本身的使用很简单,但混入了平台专有数字类型后,会
|Float64 |64bit |2.2250738585072014E-308 |1.7976931348623157E308 |双精度浮点型,等同Double|
|Double |64bit |2.2250738585072014E-308 |1.7976931348623157E308 |双精度浮点型|
**注意:**
-
Swift 中 Int 类型是根据平台动态的,在 32 位设备下等同于 Int32, 在64位设备下等同于 Int64。因此建议整型使用 Int, 除非必要,且在保证不会溢出的场景下才使用 Int32、Int64。
-
同样,Swift 中的 UInt 类型也是根据平台动态的,在 32 位设备下等同于 UInt32, 在64位设备下等同于 UInt64。建议使用 UInt,非必要不使用 UInt32、UInt64。
-
Float16 在 iOS14.0 及以上系统上才能使用,使用时注意做系统版本号判断。
[
参考
](
https://uniapp.dcloud.net.cn/plugin/uts-uni-api.html#设备
)
...
...
@@ -132,7 +138,8 @@ js的专用数字类型是BigInt。[详见](https://developer.mozilla.org/zh-CN/
使用下面的方法,虽然可能会被编辑器报语法错误(后续HBuilderX会修复这类误报),但编译到 kotlin 和 swift 运行是正常的。
-
声明特定的平台数字类型
> 平台专有数字类型,均为首字母大写,注意与 number 首字母小写是不同的
> 平台专有数字类型,均为首字母大写,注意与 number 首字母小写是不同的
```
ts
// #ifdef APP
...
...
@@ -186,19 +193,23 @@ a 会被自动推导成什么类型?是Int、double、还是number?值是0
-
规则1. 在定义变量时,若没有显式声明变量类型,通过数字字面量以及数字字面量组成的运算表达式来给变量赋值,此时变量类型默认推导为 number类型
举例说明:
*
HBuilderX3.9前,运行到App,由kotlin和swift编译器推导
```
ts
let
a
=
1
// 类型为Int
let
b
=
1
/
10
// 类型为Int,值为0
```
*
HBuilderX3.9起,运行到App,未显式声明类型的变量,需根据数字字面量推导变量类型,此时由 uts 编译器推导,变量类型默认为 number
```
ts
let
a
=
1
// 类型为number
let
b
=
1
/
10
// 类型为number,值为0.1
```
如您已经显式声明变量类型,无需自动推导,则不受上述规则变化影响。不管HBuilderX 3.9之前还是之后,以下代码都是一样的
```
ts
let
a
:
Int
=
1
// 类型为Int
```
...
...
@@ -208,8 +219,9 @@ let a:Int = 1 // 类型为Int
但
`let b:Int = 1/10`
会在 HBuilderX 3.9+起报错,原因见下面第二条规则。
再澄清下规则1:
*
如果定义变量时已经显式声明了类型,和规则1无关
*
如果不是定义变量,和规则1无关
*
如果定义变量时已经显式声明了类型,和规则1无关
*
如果不是定义变量,和规则1无关
也就是如下代码中,
`60`
这个字面量的处理,和规则1无关,不会把这个
`60`
改为number类型
...
...
@@ -223,6 +235,7 @@ test(60) // 这个60可以正常传入,无论HBuilderX 3.9之前还是之后
-
规则2. 纯数字字面量的除法,其结果会变成number
在HBuilderX 3.9以前,字面量除法也由kotlin和swift自动推导,kotlin下存在一个问题,看如下代码:
```
ts
function
test
(
score
:
number
):
boolean
{
return
(
score
>=
60
)
...
...
@@ -237,13 +250,15 @@ test(1/10) // 报错,类型不匹配。需要number而传入Int
引入这个规则后,上述代码就可以正常运行了。
这里的
`纯数字字面量的除法`
,指除法表达式中除了数字和运算符,不包括任何其他东西:
-
比如变量:
`let a:Int=1;let b:Int= a/1`
-
比如使用 as 断言:
`(1 as Int)/10`
以上除法表达式,都不是“纯数字字面量的除法”,都不会被推导为number。
以上除法表达式,都不是“纯数字字面量的除法”,都不会被推导为number。
但是这条规则,也会导致一个
**向下兼容问题**
。
下面的代码在HBuilderX 3.9之前是可以正常运行的,但在3.9起会报错,因为1.0/10被转为了number类型,传入需要Double的函数时就会类型不匹配。
```
ts
function
test
(
score
:
Double
):
boolean
{
return
(
score
>=
60.0
)
...
...
@@ -252,6 +267,7 @@ test(1.0/10)
```
在HBuilderX 3.9后,为了正确传入Double,要注意跳过规则2。避免纯数字字面量除法,所以正确的写法是:
```
ts
function
test
(
score
:
Double
):
boolean
{
return
(
score
>=
60.0
)
...
...
@@ -271,19 +287,19 @@ test((1.0 as Double)/10) //表达式中任意一个数字as一下,都不会走
所有的 number 都支持下列方法进行转换(部分类库API使用java编写,其要求的java类型与下列kotlin类型完全一致,可以直接使用
*
toByte(): Byte
*
toShort(): Short
*
toInt(): Int
*
toLong(): Long
*
toFloat(): Float
*
toDouble(): Double
*
toByte(): Byte
*
toShort(): Short
*
toInt(): Int
*
toLong(): Long
*
toFloat(): Float
*
toDouble(): Double
另外 number 还具备下列函数进行整型的无符号转换,这部分API 在jvm上没有对应的原始数据类型,主要的使用场景是 色值处理等专业计算场景的
`多平台拉齐`
*
toUByte(): UByte
*
toUShort(): UShort
*
toUInt(): UInt
*
toULong(): ULong
*
toUByte(): UByte
*
toUShort(): UShort
*
toUInt(): UInt
*
toULong(): ULong
```
ts
let
a
:
number
=
3
...
...
@@ -300,6 +316,7 @@ i.toDouble() // 转换为 Double 类型
```
把 kotlin 专有数字类型,转换为number,使用Number.from()方法
```
ts
let
a
:
Int
=
1
let
a1
=
Number
.
from
(
a
)
// Int转number
...
...
@@ -378,6 +395,7 @@ s3 = "abc"
app-ios平台上原生有 NSString ,某些系统API或者三方库API可能使用NSString类型的字符串参数或者返回值。
定义NSString
```
ts
let
nstr
=
NSString
(
string
=
"
123
"
)
// 类型为NSString
```
...
...
@@ -385,6 +403,7 @@ let nstr = NSString(string="123") // 类型为NSString
可按照下面的方法在 string 和 NSString 之间转换:
-
string 转 NSString
```
ts
let
str
=
"
abcd
"
// 类型为string
// 方式一:
...
...
@@ -394,6 +413,7 @@ let nstr2 = str as NSString // 类型为NSString
```
-
NSString 转 string
```
ts
let
nstr3
=
NSString
(
string
=
"
123
"
)
// 类型为NSString
// 方式一:
...
...
@@ -409,7 +429,6 @@ let str5 = nstr3 as string // 类型为string
*
编译至 Kotlin 平台时,最大长度受系统内存的限制,超出限制会报错:
`java.lang.OutOfMemoryError: char[] of length xxx would overflow`
。
*
编译至 Swift 平台时,最大长度也受系统内存的限制,超出限制目前没有返回信息。
#### Android 中的 Char 和 CharArray
app-android平台存在一种
`kotlin.Char`
类型
[
文档地址
](
https://kotlinlang.org/docs/characters.html
)
,与UTS中长度为1的字符串比较类似。
...
...
@@ -442,7 +461,6 @@ arrayMock.add("l".toCharArray()[0])
arrayMock.add("o".toCharArray()[0])
console.log(arrayMock.joinToString(""));
```
## any类型 @any
...
...
@@ -658,6 +676,7 @@ let javaDate = new JavaDate(utsDate.getTime().toLong())
```
+
java.util.Date 转 Date
```
uts
import JavaDate from 'java.util.Date' ;
...
...
@@ -665,7 +684,63 @@ let javaDate = new JavaDate(1709208329000)
let utsDate = new Date(javaDate.getTime())
```
## 字节数组(ArrayBuffer)@arrayBuffer
ArrayBuffer对象用来表示通用的原始二进制数据缓冲区。它是一个字节数组,通常在其他语言中称为byte array。你不能直接操作ArrayBuffer中的内容;而是要通过类型化数组对象对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。
### 定义字节数组
```
ts
//直接使用ArrayBuffer初始化类型化数组
const
buffer
=
new
ArrayBuffer
(
8
);
const
view
=
new
Int32Array
(
buffer
);
// 使用of方法
var
array
=
Int32Array
.
of
(
1
,
2
,
3
)
//使用from方法
var
array
=
Int32Array
.
from
([
1
,
2
,
3
],
(
v
:
number
,
_
:
number
)
:
number
=>
v
+
v
);
//ArrayBuffer.fromByteBuffer() 静态方法用于将android 原生的ByteBuffer对象转换为ArrayBuffer
var
byteBuffer
=
ByteBuffer
.
allocate
(
100
)
byteBuffer
.
put
(
1
)
byteBuffer
.
put
(
2
)
var
buffer
=
ArrayBuffer
.
fromByteBuffer
(
byteBuffer
)
console
.
log
(
'
arraybuffer_toByteBuffer
'
,
buffer
)
//ArrayBuffer 实例的 toByteBuffer() 方法返回一个android原生ByteBuffer对象。
byteBuffer
=
buffer
.
toByteBuffer
()
console
.
log
(
'
arraybuffer_toByteBuffer
'
,
byteBuffer
)
byteBuffer
.
rewind
()
console
.
log
(
byteBuffer
[
0
])
//1
console
.
log
(
byteBuffer
[
1
])
//2
```
### 类型化数组对象
[
Float32Array
](
https://doc.dcloud.net.cn/uni-app-x/uts/buildin-object-api/float32array.html
)
[
Float64Array
](
https://doc.dcloud.net.cn/uni-app-x/uts/buildin-object-api/float64array.html
)
[
Int8Array
](
https://doc.dcloud.net.cn/uni-app-x/uts/buildin-object-api/int8array.html
)
[
Int16Array
](
https://doc.dcloud.net.cn/uni-app-x/uts/buildin-object-api/int16array.html
)
[
Int32Array
](
https://doc.dcloud.net.cn/uni-app-x/uts/buildin-object-api/int32array.html
)
[
Uint8Array
](
https://doc.dcloud.net.cn/uni-app-x/uts/buildin-object-api/uint8array.html
)
[
Uint8ClampedArray
](
https://doc.dcloud.net.cn/uni-app-x/uts/buildin-object-api/uint8clampedarray.html
)
[
Uint16Array
](
https://doc.dcloud.net.cn/uni-app-x/uts/buildin-object-api/uint16array.html
)
[
Uint32Array
](
https://doc.dcloud.net.cn/uni-app-x/uts/buildin-object-api/uint32array.html
)
[
DataView
](
https://doc.dcloud.net.cn/uni-app-x/uts/buildin-object-api/dataview.html
)
### 更多API
ArrayBuffer作为内置对象,还有更多API,
[
详见
](
buildin-object-api/arraybuffer.md
)
## 数组(Array)@array
...
...
@@ -680,6 +755,7 @@ Array,即数组,支持在单个变量名下存储多个元素,并具有执
如果开发者需要使用原始的kotlin的不可变长的Array,需使用
`kotlin.Array`
。
需要使用平台专有数组类型的场景,也是如下2种情况:
1.
某些系统API或三方原生SDK的入参或返回值强制指定了kotlin的原生数组类型。
2.
uts新增的可动态变长的Array,在性能上不如固定length、不可变长的原始kotlin.Array。但也只有在巨大量的运算中才能体现出毫秒级的差异。
...
...
@@ -707,11 +783,13 @@ let a2:Array<number> = []; //定义一个数字类型的空数组
```
3.
使用[]定义数组项的类型
```
ts
const
a1
:
string
[]
=
[
'
a
'
,
'
b
'
,
'
c
'
];
//表示数组内容都是string
```
4.
创建数组对象
```
ts
let
a1
=
new
Array
(
1
,
2
,
3
);
//支持
let
a2
=
new
Array
(
1
,
'
2
'
,
3
);
//安卓平台支持, iOS 平台不支持,在 iOS 中创建 Any[] 数组请直接使用数组字面量,如 let a2 = [1. '2', 3]
...
...
@@ -720,6 +798,7 @@ let a4 = Array(1,'2','3');//安卓平台支持, iOS 平台不支持,在 iOS
```
5.
uvue的data定义数组
```
ts
export
default
{
data
()
{
...
...
@@ -743,10 +822,8 @@ console.log(a1 instanceof Array) // 返回true
-
注意:uts 不支持以 Array(arrayLength) 指定数组长度的方式创建一个数组。
```
ts
// 下面的写法中,a1 将是一个当前 length 为1, 元素是 100 的整型数组。而不是 length 为 100 ,由 100 个空槽组成的数组。
const
a1
:
Array
(
100
);
// [100], 当前数组长度为1
```
### 遍历数组对象
...
...
@@ -767,15 +844,15 @@ array1.forEach((element:string, index:number) => {
#### kotlin专有数组类型
-
专有数组类型清单
*
kotlin.collections.List
*
kotlin.Array
*
kotlin.Int
Array
*
kotlin.Floa
tArray
*
kotlin.Byte
Array
*
kotlin.Long
Array
*
kotlin.Char
Array
*
...
*
kotlin.collections.List
*
kotlin.
Array
*
kotlin.In
tArray
*
kotlin.Float
Array
*
kotlin.Byte
Array
*
kotlin.Long
Array
*
kotlin.CharArray
*
...
-
专有数组类型定义方式
```
ts
...
...
@@ -790,8 +867,7 @@ let kotlinArray = arrayOf("hello","world")
统一使用
`Array.fromNative`
将专有数据类型转换为 Array,下面列出了常见的场景:
```
ts
// kotlin.collections.List 转换 Array
// kotlin.collections.List 转换 Array
let
kotlinList
=
mutableListOf
(
"
hello
"
,
"
world
"
)
let
utsArr1
=
Array
.
fromNative
(
kotlinList
)
...
...
@@ -818,12 +894,8 @@ let kotlinArray = arrayOf("hello","world")
// kotlin.CharArray 即 java 中的 char[]
let
b5
=
charArrayOf
(
Char
(
66
),
Char
(
66
),
Char
(
81
))
let
c5
=
Array
.
fromNative
(
b5
)
```
举个例子。如下代码向系统查询了有多少应用可以响应
`launcher`
行为 ,返回的 resolveInfo 是一个
`List<ResolveInfo>`
。
```
ts
...
...
@@ -872,18 +944,14 @@ let b = a.toKotlinList().map(function(it):Float{
let
c
=
b
.
toTypedArray
()
// d 是 FloatArray
let
d
=
b
.
toFloatArray
()
```
+
特别说明:
`Byte`
类型在
`kotlin`
中使用场景较为广泛,除表示数字,还常见于
`kotlin.ByteArray`
形式表示 文件,网络数据 等字节流。
下面列出了
`kotlin.ByteArray`
的常用转换代码:
```
uts
import Charsets from 'kotlin.text.Charsets'
// 将ByteArray 以 ascii 编码转换为字符串
...
...
@@ -892,77 +960,67 @@ let str = byteArrayOf(65,66,67).toString(Charsets.ISO_8859_1)
const str: string = 'hello world!'
// 字符串以UTF-8编码转换为 ByteArray
const bytes: ByteArray = str.toByteArray(Charsets.UTF_8)
```
更多
`kotlin.ByteArray`
的用法参考
[
文档
](
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-byte-array/
)
#### iOS 平台专有数组类型
>UTS 中的 Array 对应到 Swift 中就是 Array, 方法是通用的,无需转换。一般情况下,使用 Array 即可。
>
>但是,某些系统或者三方库 API 可能会要求 OC 的 NSArray、NSMutableArray 类型的数组,这个时候就需要进行转换。
>
UTS 中的 Array 对应到 Swift 中就是 Array, 方法是通用的,无需转换。一般情况下,使用 Array 即可。
>
>
但是,某些系统或者三方库 API 可能会要求 OC 的 NSArray、NSMutableArray 类型的数组,这个时候就需要进行转换。
-
专有数组类型清单
*
NSArray
*
NSMutable
Array
*
NS
Array
*
NSMutableArray
-
专有数组类型定义方式
1.
创建 NSArray
> NSArray 是 OC 中的不可变数组,顾名思义,数组创建完成之后就不可以再添加或者删除元素。因此,创建 NSArray 对象时就应该完成数组的初始化。可以通过以下方式创建 NSArray:
```ts
// 方式一: 创建一个空数组,注意数组创建后就不可改变,不能再添加或者删除元素,应避免使用该方式。
let a: NSArray = NSArray()
// 方式二: 用一个数组创建一个 NSArray, 推荐使用。同样,创建完成后数组不可变。
let b: NSArray = NSArray(array=[1, 2, 3, 4]) // 等价于 any[],注意:不是等价于 number[]
// 方式三: 用一个元素定义 NSArray, 不推荐使用
let c: NSArray = NSArray(object=1)
// 方式四:用不定长元素定义 NSArray, 可以使用
let d: NSArray = NSArray(objects=1, "2", false, "ok")
```
> NSArray 是 OC 中的不可变数组,顾名思义,数组创建完成之后就不可以再添加或者删除元素。因此,创建 NSArray 对象时就应该完成数组的初始化。可以通过以下方式创建 NSArray:
```
ts
// 方式一: 创建一个空数组,注意数组创建后就不可改变,不能再添加或者删除元素,应避免使用该方式。
let
a
:
NSArray
=
NSArray
()
// 方式二: 用一个数组创建一个 NSArray, 推荐使用。同样,创建完成后数组不可变。
let
b
:
NSArray
=
NSArray
(
array
=
[
1
,
2
,
3
,
4
])
// 等价于 any[],注意:不是等价于 number[]
// 方式三: 用一个元素定义 NSArray, 不推荐使用
let
c
:
NSArray
=
NSArray
(
object
=
1
)
// 方式四:用不定长元素定义 NSArray, 可以使用
let
d
:
NSArray
=
NSArray
(
objects
=
1
,
"
2
"
,
false
,
"
ok
"
)
```
2.
创建 NSMutableArray
-
NSMutableArray 是 OC 中的可变数组,其是 NSArray 的子类,可变数组创建后可以增加或者删除元素。NSArray 的所有创建方式也都适用于 NSMutableArray
```
ts
// 方式一: 创建一个空数组,其类型等价于 any[]
let
a
:
NSMutableArray
=
NSMutableArray
()
a
.
add
(
1
)
//添加一个元素
a
.
add
(
"
22
"
)
//添加一个元素
a
.
add
(
false
)
//添加一个元素
a
.
remove
(
1
)
//移除一个元素
a
.
removeObject
(
at
=
2
)
//移除一个指定下标的元素
a
.
removeAllObjects
()
//移除全部元素
a
.
removeLastObject
()
//移除最后一个元素
// 方式二: 用一个数组创建一个 NSMutableArray, 推荐使用。
let
b
:
NSMutableArray
=
NSMutableArray
(
array
=
[
1
,
2
,
3
,
4
])
// 等价于 any[],注意:不是等价于 number[]
// 方式三: 用一个元素定义 NSMutableArray
let
c
:
NSMutableArray
=
NSMutableArray
(
object
=
1
)
// 方式四:用不定长元素定义 NSMutableArray
let
d
:
NSMutableArray
=
NSMutableArray
(
objects
=
1
,
"
2
"
,
false
,
"
ok
"
)
```
```
ts
// 方式一: 创建一个空数组,其类型等价于 any[]
let
a
:
NSMutableArray
=
NSMutableArray
()
a
.
add
(
1
)
//添加一个元素
a
.
add
(
"
22
"
)
//添加一个元素
a
.
add
(
false
)
//添加一个元素
a
.
remove
(
1
)
//移除一个元素
a
.
removeObject
(
at
=
2
)
//移除一个指定下标的元素
a
.
removeAllObjects
()
//移除全部元素
a
.
removeLastObject
()
//移除最后一个元素
// 方式二: 用一个数组创建一个 NSMutableArray, 推荐使用。
let
b
:
NSMutableArray
=
NSMutableArray
(
array
=
[
1
,
2
,
3
,
4
])
// 等价于 any[],注意:不是等价于 number[]
// 方式三: 用一个元素定义 NSMutableArray
let
c
:
NSMutableArray
=
NSMutableArray
(
object
=
1
)
// 方式四:用不定长元素定义 NSMutableArray
let
d
:
NSMutableArray
=
NSMutableArray
(
objects
=
1
,
"
2
"
,
false
,
"
ok
"
)
```
-
专有数组类型 转 Array
```
ts
// 将 NSArray 转成 Array
let
a
:
NSArray
=
NSArray
(
array
=
[
1
,
2
,
3
,
4
])
// 等价于 any[],注意:不是等价于 number[]
let
a1
=
Array
(
a
)
...
...
@@ -970,7 +1028,6 @@ let a1 = Array(a)
// 将 NSMutableArray 转成 Array
let
b
:
NSMutableArray
=
NSMutableArray
(
array
=
[
1
,
2
,
3
,
4
])
// 等价于 any[],注意:不是等价于 number[]
let
b1
=
Array
(
b
)
```
-
Array 转 专有数组类型
...
...
@@ -988,15 +1045,14 @@ let a2 = a as NSArray
// Array 转换成 NSMutableArray
let
a3
:
NSMutableArray
=
NSMutableArray
(
array
=
a
)
```
**注意:**
+
无论是 NSArray 还是 NSMutableArray 对象创建后都等价于 any[] 类型的数组,此时 Swift 不再有类型推导,可以往可变数组中添加任意类型的非空元素。
+
NSArray 和 NSMutableArray 类型的数组不接受空值 null, 任何情况下不要往这两种类型中注入 null。 否则,在运行时可能会引起应用闪退。
+
Array 类型不能通过 as 方式转换成 NSMutableArray 类型。 但是可以通过 as 方式 转换成 NSArray 类型。
+
Swift 中的 Array 是值类型,其和 TS 中 Array 的一点区别是 可以通 == 判断两个数组是否相等,只要两个数组的类型和元素一样,判等的结果就是 true。
+
无论是 NSArray 还是 NSMutableArray 对象创建后都等价于 any[] 类型的数组,此时 Swift 不再有类型推导,可以往可变数组中添加任意类型的非空元素。
+
NSArray 和 NSMutableArray 类型的数组不接受空值 null, 任何情况下不要往这两种类型中注入 null。 否则,在运行时可能会引起应用闪退。
+
Array 类型不能通过 as 方式转换成 NSMutableArray 类型。 但是可以通过 as 方式 转换成 NSArray 类型。
+
Swift 中的 Array 是值类型,其和 TS 中 Array 的一点区别是 可以通 == 判断两个数组是否相等,只要两个数组的类型和元素一样,判等的结果就是 true。
### 更多API
...
...
@@ -1031,7 +1087,6 @@ const myMap = new Map<number,string>([
[
2
,
"
two
"
],
[
3
,
"
three
"
],
]);
```
注意在HBuilderX中console.log一个Map时,返回内容格式如下:
...
...
@@ -1043,6 +1098,7 @@ const myMap = new Map<number,string>([
开头的[Object]代表其typeof的类型,Map代表它的实际类型,(3)是map的size,{...} 是Map的内容。
还可以把一个UTSJSONObject转为Map
```
ts
let
userA
=
{
name
:
"
zhangsan
"
,
...
...
@@ -1053,6 +1109,7 @@ let userMap = userA.toMap() //UTSJSONObject有toMap方法
```
### 验证类型
```
ts
console
.
log
(
typeof
map1
);
//返回 object
console
.
log
(
map1
instanceof
Map
);
//返回 true
...
...
@@ -1086,6 +1143,7 @@ UTSJSONObject,是一个类型,可以在变量的冒号后面使用,本节
首先,我们需要区分JSON对象,和由JSON对象组成的数组。
这是一个 UTSJSONObject 对象。jo 对象有2个属性,x和y,都是数字类型(类型没有声明是因为根据字面量自动推导了)
```
ts
let
jo
:
UTSJSONObject
=
{
"
x
"
:
1
,
...
...
@@ -1094,6 +1152,7 @@ let jo: UTSJSONObject = {
```
这是一个 UTSJSONObject 数组。其数组项里有2个 UTSJSONObject 对象,每个对象都有x和y这2个属性。注意
`=`
左边有
`[]`
来表示这是一个数组类型。
```
ts
let
jr
:
UTSJSONObject
[]
=
[
{
"
x
"
:
1
,
"
y
"
:
2
},
...
...
@@ -1104,6 +1163,7 @@ let jr: UTSJSONObject[] = [
在 js 中,可以定义一个变量,随意接受对象字面量或数组字面量。但在 UTS 里不行。如果数据内容是数组字面量,就不能定义为 UTSJSONObject。
也就是下面的代码是错误的,不能把数组赋值给对象。在接收网络传输的json数据时,非常需要注意这个类型匹配问题。类型不匹配会造成代码错误和应用崩溃。
```
ts
let
jo
:
UTSJSONObject
=
[{
"
x
"
:
1
,
...
...
@@ -1140,6 +1200,7 @@ let jo2 = {
```
关于属性名是否需要使用引号包围的规则:
1.
如果是对象字面量赋值,普通属性名称无需使用引号包围,但使用也没问题
2.
如果是对象字面量赋值,且属性名包括特殊符号,如:
`-`
,则必须两侧加引号包围。
3.
如果是JSON.parse()方法入参需要的字符串,则属性名必须使用双引号包围(web端规则也是如此)
...
...
@@ -1178,6 +1239,7 @@ let jo = JSON.parse(s) // 这个代码适用于HBuilderX 3.9以前
所以从 HBuilderX 3.9起,
`JSON.parse()`
返回的类型改为
`any`
,即可能返回对象、也可能返回数组。这样就需要开发者自行再
`as`
一下来指定具体类型了。
新的写法是这样:
```
ts
let
s
=
`{"result":true, "count":42}`
// 常见场景中,这个字符串更多来自于网络或其他应用传输。
let
jo
=
JSON
.
parse
(
s
)
as
UTSJSONObject
...
...
@@ -1187,6 +1249,7 @@ let jr = JSON.parse(s) as UTSJSONObject[]
```
当然,还有更简短的写法,使用HBuilderX 3.9新增的
`JSON`
的parseObject()和parseArray()方法:
```
ts
let
s
=
`{"result":true, "count":42}`
// 常见场景中,这个字符串更多来自于网络或其他应用传输。
let
jo
=
JSON
.
parseObject
(
s
)
...
...
@@ -1210,7 +1273,6 @@ js平台同时存在object和UTSJSONObject,且UTSJSONObject继承自object。
例如:
```
ts
type
Person
=
{
age
:
number
}
...
...
@@ -1259,11 +1321,13 @@ merge(
```
在js平台,UTSJSONObject和object在日常使用时差别不大,但有如下几点差别:
1.
UTSJSONObject多了一批通过keypath操作数据的方法
[
见下
](
#keypath
)
2.
UTSJSONObject继承自object,原型链位置不同
3.
instanceof返回值不同
### 验证类型
```
ts
let
jo
=
{
x
:
1
,
...
...
@@ -1289,19 +1353,25 @@ let rect = {
以上述 rect 为例,访问 UTSJSONObject 中的数据,有如下3种方式:
#### 1. `.` 操作符
即
`rect.x`
、
`rect.size.width`
。
这种写法比较简单,和js习惯一致,但在 UTS 存在以下限制:
- 仅限于web,在iOS/Android不支持`.`操作符。
```
即 `rect.x`、`rect.size.width`。
这种写法比较简单,和js习惯一致,但在 UTS 存在以下限制:
- 仅限于web,在iOS/Android不支持`.`操作符。
```
#### 2. `[""]` 下标
即
`rect["x"]`
。
这是一种通用的方式,不管通过字面量定义的 UTSJSONObject,还是通过 `JSON.parse()`,不管是 web、Android、iOS 哪个平台,都可以使用下标方式访问 UTSJSONObject 属性。
```
即 `rect["x"]`。
这是一种通用的方式,不管通过字面量定义的 UTSJSONObject,还是通过 `JSON.parse()`,不管是 web、Android、iOS 哪个平台,都可以使用下标方式访问 UTSJSONObject 属性。
但下标返回的数据,类型是any,想继续使用需要`as`为具体类型。
但下标返回的数据,类型是any,想继续使用需要`as`为具体类型。
尤其是有子对象时,需要 `as` 后才能继续访问下一层数据。
尤其是有子对象时,需要 `as` 后才能继续访问下一层数据。
```
```
ts
let
rect
=
{
...
...
@@ -1330,7 +1400,6 @@ console.log((rect["size"] as UTSJSONObject)["width"]) //80 使用as后需要整
console
.
log
(
rect
.
border
[
0
].
color
);
//报错,一旦使用了下标访问数组,后面就无法使用.操作符了
console
.
log
(
rect
.
border
[
0
][
"
color
"
]);
// red 但iOS无法使用.操作符
console
.
log
((
rect
[
"
border
"
]
as
UTSJSONObject
[])[
0
][
"
color
"
]);
// red
```
如果是
`JSON.parse`
解析的数据,只能通过下标访问,无法使用
`.`
操作符。因为
`.`
操作符的成立建立在编译器可确定类型的前提,字面量直接赋值可识别类型,
`JSON.parse`
无法识别类型。
...
...
@@ -1343,6 +1412,7 @@ console.log(listArr[0]["title"]); //第一组
```
多层级下标访问时需要使用 as 转换为 UTSJSONObject 或
`UTSJSONObject[]`
```
ts
var
j
=
{
"
subobj
"
:{
...
...
@@ -1361,6 +1431,7 @@ keypath是把`.`操作符作为一个字符串传入了UTSJSONObject的一个方
相对于受限制
`.`
和需要经常as的下标,更推荐使用keyPath方式来操作UTSJSONObject。
以下面的 UTSJSONObject 为例
```
ts
let
utsObj
=
{
"
username
"
:
"
zhangsan
"
,
...
...
@@ -1388,6 +1459,7 @@ console.log(utsObj.getString("一个不存在属性")) // 打印结果:null
```
需要特别注意的是:属性名 和 属性类型,都要正确,否则不会返回对应的属性结果
```
ts
console
.
log
(
utsObj
.
getNumber
(
"
age
"
))
// 打印结果:12
console
.
log
(
utsObj
.
getNumber
(
"
agee
"
))
// 名字不对,打印结果:null
...
...
@@ -1424,7 +1496,6 @@ console.log(obj.getBoolean('data[2][0].b')) // 打印结果:true
console
.
log
(
obj
.
getJSON
(
'
data[2][1]
'
))
// 打印结果:{"b":"test"}
console
.
log
(
obj
.
getArray
(
'
data[3]
'
))
// 打印结果:[1, 2, 3]
console
.
log
(
obj
.
getAny
(
'
data[1].a
'
))
// 打印结果:2
```
在所有的getXXX函数中
`getAny`
是一个特殊的存在,它可以获取属性,而不要求限制类型,他的返回值是 any 类型。
...
...
@@ -1439,6 +1510,7 @@ console.log(utsObj.getAny("address") as UTSJSONObject)
```
除了直接使用UTSJSONObject外,在 uts 中使用json数据还有2种方式:
1.
UTSJSONObject.toMap() 转为Map对象
[
见上
](
#map
)
2.
把json字符串或对象字面量通过type转为自定义类型,这是ts里经常使用的方式
[
见下
](
#type
)
...
...
@@ -1450,7 +1522,6 @@ console.log(utsObj.getAny("address") as UTSJSONObject)
UTSJSONObject对象还有很多API,
[
详见
](
buildin-object-api/utsjsonobject.md
)
## type自定义类型@type
`type`
是关键字,用于给一个类型起别名,方便在其他地方使用。
...
...
@@ -1519,6 +1590,7 @@ console.log(personList[0].name); //返回zhangsan
### null的处理
但是需要注意,json数据可能不规范,有些属性缺失,此时就需要在定义type时设可为空:
```
ts
type
PersonType
=
{
id
:
number
,
...
...
@@ -1583,6 +1655,7 @@ type PersonType = {
这里还要注意代码的执行顺序,执行
`address: PersonAddress`
时,这个类型必须已经被定义过。所以要被引用的类型必须定义在前面,后面才能使用这个类型。
那么嵌套的完整写法例子:
```
ts
type
PersonAddressType
=
{
city
:
string
,
...
...
@@ -1607,6 +1680,7 @@ console.log(person.address.city) //beijing
```
注意,在HBuilderX 3.9以前,有子对象的对象字面量或UTSJSONObject,无法直接被 as 为有嵌套的type,也需要对子对象进行 as 。
```
ts
let
person
=
{
id
:
1
,
...
...
@@ -1638,6 +1712,7 @@ console.log(person?.name); // 返回zhangsan。由于person可能为null,pars
```
注意上述代码中,如果
`let person`
时,想使用冒号定义类型,需要考虑parse失败的情况,要这么写:
```
ts
type
PersonType
=
{
id
:
number
,
...
...
@@ -1648,6 +1723,7 @@ console.log(person?.name); // 返回zhangsan
```
或者如果你确保jsonString的值一定是合法的、parse一定可以成功,那么也可以在定义的末尾!号断言,告诉编译器肯定没有问题,那么此后就可以不使用
`?.`
了
```
ts
type
PersonType
=
{
id
:
number
,
...
...
@@ -1660,6 +1736,7 @@ console.log(person.name); // 返回zhangsan
使用!断言,是强制编译器信任开发者的写法,编译器放过后,在运行期一旦person为null,调用
`person.name`
就会崩溃。而使用
`person?.name`
则不会崩溃,只会返回null。
#### 敏感字和符号@json_field
在定义Type时键名必须符合变量命名规则(如第一个字符不能数字,不能包含空格或运算符,不能使用语言保留的关键字等),
如果json字符串中的键名不符合变量命名规则,比如有个key的名字叫"a+b",这种json转type会失败。
...
...
@@ -1676,17 +1753,20 @@ type ExampleType = {
a_b
:
string
}
```
以上示例定义的 ExampleType 类型,在
`a_b: string`
声明时添加注释
`@JSON_FIELD "a+b"`
,表示:
-
JSON.parse 时会将json字符中的键名"a+b"转换为ExampleType类型的"a_b"属性;
-
JSON.stringify 时会将ExampleType类型的"a_b"属性转换为json字符串中的"a+b"键名。
推荐的转换规则如下:
-
将不合法的字符(如空格、运算符等)转换为下划线“_”,如“a+b”转换为“a_b”
-
将保留
[
关键词
](
keywords.md
)
(如class、enum等)转换时,在前面添加下划线,如“class”转换为“_class”
-
如果转换后的名称已存在,在后面添加下划线
`_`
避免冲突,如同时存在“a+b”和“a-b”,分别转换为
`a_b`
和
`a_b_`
以下举例json字符串
`{"a+b":"addition value","a-b":"subtraction value","class":"classification value"}`
,应该如何定义 type 才能使用 JSON.parse 转换
```
ts
type
SpecialType
=
{
/**
...
...
@@ -1718,7 +1798,7 @@ let t:SpecialType = {
console
.
log
(
JSON
.
stringify
(
t
))
//输出: {"a+b":"value 1","a-b":"value 2","class":"value 3"}
```
>以上`@JSON_FIELD`注释规则需要HBuilderX3.9.0+版本支持
>
以上`@JSON_FIELD`注释规则需要HBuilderX3.9.0+版本支持
#### json转type工具
...
...
@@ -1737,6 +1817,7 @@ HBuilderX 3.9起内置了一个json转type工具,在`json编辑器`中选择
### 为vue的data中的json定义类型
uvue文件中data中的json数据也涉及类型定义。此时注意:type定义必须放在
`export default {}`
前面。
```
html
<script>
type
PersonType
=
{
...
...
@@ -1763,8 +1844,8 @@ uvue文件中data中的json数据也涉及类型定义。此时注意:type定
由于篇幅较长,示例另见:
[
request教程
](
../tutorial/request.md
)
### type 类型的遍历
> HBuilderX3.9+
uts 为自定义 type 类型提供了迭代器,可以使用 for-in 遍历出 type 类型中的所有属性名
...
...
@@ -1775,10 +1856,10 @@ let person : PersonType = { id: 1, name: "zhangsan", age: 18 }
for
(
let
key
in
person
)
{
console
.
log
(
key
)
// 输出 "id", "name", "age"
}
```
### type 类型的下标访问
> HBuilderX3.9+
uts 为自定义 type 类型提供了下标操作,在适当的时机,可以使用下标的方式来读取或者修改 type 类型的属性值。
...
...
@@ -1792,10 +1873,8 @@ console.log(person["id"]) //1
obj
[
"
age
"
]
=
25
console
.
log
(
obj
[
"
age
"
])
//25
console
.
log
(
obj
.
age
)
//25
```
## undefined
js中的 undefined类型表示变量被定义,但是未赋值或初始化。
...
...
@@ -1813,11 +1892,13 @@ uts有`运行时类型`和`开发时类型`的概念区别。
目前支持的
`开发时类型`
有:
### 相同运行时类型的字面量联合类型@literal-union-type
字面量联合类型,指相同类型的数字或字符串字面量,把多个字面量值以或的方式赋值给一个类型。
它常常用于在开发阶段的值域约束。
比如以下例子里,a1的值域只能是302或404或500,而b1的值域只能是"get"或"post"。
```
ts
// 注意不要写在uvue页面的export default里面
type
a
=
302
|
404
|
500
...
...
@@ -1834,6 +1915,7 @@ b1=="get1" // 当为b1赋值不在值域范围的新值时,ide会报红
相同字面量联合类型,在方法的参数值域定义里很常见。
但有几个注意:
1.
这些字面量必须是一个类型,或者统一是数字,或者统一是字符串。
2.
字面量联合类型只是
`开发时类型`
,在运行时,类型会变为number或string。
...
...
@@ -1843,8 +1925,8 @@ b1=="get1" // 当为b1赋值不在值域范围的新值时,ide会报红
上一节提到的字符串字面量联合类型,其实是一种枚举型的值域范围约束。
但很多值域无法通过枚举表达。
\
比如string.ColorString,代表一个合法的颜色字符串,"red"、"#000",这些是它的合法值域。
\
但很多值域无法通过枚举表达。
比如string.ColorString,代表一个合法的颜色字符串,"red"、"#000",这些是它的合法值域。
再比如string.IDString代表页面上合法的组件的id属性值清单,string.ImageURIString则代表工程下合法的图片路径清单。
HBuilder支持给变量定义特殊值域string类型,这些类型在HBuilder里都可以得到更好的代码提示和语法校验。
...
...
@@ -1856,6 +1938,7 @@ HBuilder支持给变量定义特殊值域string类型,这些类型在HBuilder
## 联合类型@union-type
由于kotlin和swift限制,uts在App平台支持的联合类型有限:
-
支持
[
|null
](
#null
)
(即可为空)
-
[
字面量联合类型
](
#literal-union-type
)
...
...
@@ -1876,3 +1959,11 @@ uts内置的类型,包括浏览器、Android、iOS内置的类型,在编译
**注意**
-
编译到js时联合类型等复杂类型在编译后会被擦除
```
```
```
```
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录