类型转换
MushScript 中,有多种类型转换的方法。
T(v):数值转换与解析
转换写成「类型名当函数」的调用形式,按源与目标的类型自动分派语义。数值转换永不失败,浮点转整数向零截断(不是四舍五入):
val trunc = int64(3.9);
print(trunc);3- 整数类型不收小数字面量,连
3.0也不收(val w: int = 3.0;)。 - 浮点常量转窄整数时编译期查值域:
int16(-40000.0f64)报 MS4211。 char的互转走码点中转:int('A')取码点,char(66)按码点构字符。
字符串源进解析通道:int("42") 得 42,bool("True")、decimal64("1.5") 同理。解析失败会抛 System.ConversionError,避错可用 try?(失败得 null):
print(try? int("42"));
print(try? int("x"));
print(try? bool("True"));42
null
Truebool / string 目标位只收字符串源。
用户转换:顶层 conversion
用户转换声明在模块顶层,类型体与扩展体内不再有转换声明(写在那里会定向报错并提示迁移到顶层)。
转换恒单参、返回类型必声明:conversion 是显式形,仅经 T(v) 消费。implicit conversion 在隐式位(赋值、传参、返回、操作数位)自动生效,同样可以被 T(v) 显式调用,但声明为 implicit 时不能再与 fail 组合。
class Meters
{
public var v: int = 0;
}
public conversion(v: int) -> Meters
{
return new Meters() { v: v };
}
public implicit conversion(m: Meters) -> int
{
return m.v;
}
func main() -> int
{
val m = Meters(42);
val n: int = m;
print(m.v, n, int(m), m + 1);
return 0;
}42 42 42 43跨模块激活经 import 门控:import moduleA; 即激活其声明的转换,未导入不可见;两个已导入模块声明了同一对转换时,使用点会报歧义错误。
从字符串解析用户类型,标准写法就是一个源为 string 的 fail conversion,失败走 fail 通道,T(v) 调用点须 try/capture 消费:
struct Celsius
{
public val C: float;
public init(c: float) { C = c; }
}
public conversion(s: string) fail System.ConversionError -> Celsius
{
return new Celsius(try float(s));
}
func main() -> int
{
val c = try? Celsius("36.5");
print(c != null);
if c != null
{
print(c.C);
}
return 0;
}True
36.5is、as 与受检转 T(v)
该使用哪一种转换方式,可以看下方的表格:
| 写法 | 返回 | 失败行为 |
|---|---|---|
is T | bool | False |
as T | T? | null |
T(v) 受检转 | 裸 T | fail System.ConversionError,须消费 |
数值标量之间 as 返回裸 T:
val viaAs = 3.9 as int64;
print(viaAs);3编译期按两侧类型的关系分级:派生到基、实现者到协议位、同型,恒成功零开销,向下转与 any 源留给运行期检查。
两个类型没有基类链也没有协议实现相连时,T(v) 编译期直接拒绝。as 对无关引用类型不拒绝,运行期得 null,对跨域目标(比如把自定义类型 as 到数值)编译期报 MS3241。受检转的结果保证是有效实例,不参与判空。
class Animal
{
public func Name() -> string { return "animal"; }
}
class Dog : Animal
{
public func Bark() { print("woof"); }
}
func Describe(a: Animal) -> int
{
val soft = a as Dog;
print(soft == null);
val hard = try? Dog(a);
print(hard != null);
return 0;
}
func main() -> int
{
Describe(new Dog());
Describe(new Animal());
return 0;
}False
True
True
Falseany 源的转型走运行期检查,协议位同样按实现链判定:
val o: any = new Dog();
print(o is Dog);
val d = o as Dog;
print(d == null);True
False当声明了(源 -> 目标)转换方法时,T(v) 走转换通道,不做引用检查。
注意
- 同家族整数之间的转换同样用调用形式(如
int8(x))。 - 显式转换在编译期检查目标类型是否存在,拼错类型名会当场报错。
