- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试为 3 维点实现一个简单的结构。出于性能原因,我想将其作为结构。我想让它通用(至少对于 System.Int32
和 System.Double
),并定义算术运算符。我计划在 F#/C# 混合解决方案中使用它。
为了简化代码,将所有内容都剥离为一维,以下是我的开头:
[<Struct>]
type Point<'T> =
val X: 'T
new(x) = { X = x}
static member inline (+) (p1: Point<'U> when 'U: (static member (+): 'U * 'U -> 'U), p2: Point<'U>): Point<'U> =
Point<_>(p1.X + p2.X)
(+)
上的类型参数运算符需要用 'U 而不是 'T 来编写,否则编译器会提示类型约束应该在 Point
的 'T 参数上.
这在 F# 中运行良好,我可以编写
let p1 = Point(2.0)
let sum = p1 + p1
在 C# 中:
var p = new Point<double>(1);
var sum = p + p;
那不编译,说 Operator + cannot by applied to operands of type Point<double> and Point<double>
如果我在 dotpeek 中查看编译后的 F# 代码,它说 +
类型运算符 Point<T>
有签名+(Point<???>,Point<???>): Point<???>
.我认为这是因为我必须根据 'U 编写类型约束,并且可能还会触发 C# 编译器找不到运算符。
我可以通过定义一个带有运算符的 F# 模块来解决这个问题:
module Ops =
let inline Add(p1, p2: Point<_>) = p1 + p2
有了它,我可以通过 Ops.Add(p1,p2)
在 C# 中进行加法运算- 但这显然不像 +
那样容易阅读运营商。
如果我尝试在顶层附加类型约束以进行添加,如下所示:
[<Struct>]
type Point<'T when 'T: (static member (+): 'T * 'T -> 'T)> =
val X: 'T
new(x) = { X = x}
static member inline (+) (p1: Point<'T>, p2: Point<'T>): Point<'T> =
Point<_>(p1.X + p2.X)
然后我在 new(x) = { X = x}
处收到编译器错误,说 This code is not sufficiently generic. The type variable ^T when ^T: (static member...) could not be generalized because it would escape its scope
.
有没有办法暴露+
C# 编译器满意的运算符?
更新:运算符标记为 inline
的事实对结果没有重大影响:我可以定义
[<Struct>]
type Nothing<'T> =
val X: 'T
new(x) = { X = x}
static member inline (+) (p1: Nothing<'T>, p2: Nothing<'T>): Nothing<'T> =
Nothing<_>(p1.X)
并使用这个+
运算符在 C# 中很好:
var p1 = new Nothing<double>(1);
var sum = p1 + p1;
最佳答案
inline
是 C# 不支持的 F# 编译器独有的功能。您必须(至少)明确定义 int32
和 double
的运算符。
内联
函数由 F# 编译器内联,将通用参数替换为编译时已知 类型。 通用 函数通常 在运行时不可调用。一些异常(exception)情况,其中实现执行动态调度(参见例如 AdditionDynamic)确实在运行时工作但比它们的 inline
d 等价物慢。另一个异常(exception)是非通用 inline
函数,其中 inline
元数据会被 C# 编译器忽略。
inline
具有传染性,所有调用 inline
函数的函数都必须 inline
自身在调用树中向上移动到被调用方的所有类型参数所在的位置在编译时已知。这解释了 ... would escape its scope
错误。因此,如果 inline
在程序集边界处结束,则这些函数不能从非 F# 项目中使用。
更新:你是对的,在没有实际使用 SRTP ( Statically Resolved Type Parameters ) 的情况下标记运算符 inline
没有效果:类型 T
没有约束,所以不需要在编译时知道:
let inline Add(p1: Nothing<'T>, p2: Nothing<'T>) = Nothing<_>(p1.X)
有签名
val inline Add : p1:Nothing<'T> * p2:Nothing<'T> -> Nothing<'T>
一旦你真正使用了inline
特性(这里是为了能够使用+
),T
就已知有一些限制:
let inline Add(p1: Nothing<_>, p2: Nothing<_>) = p1.X + p2.X
有签名
val inline Add :
p1:Nothing< ^a> * p2:Nothing< ^b> -> ^c
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
从 C# 的角度来看:
// normal (runtime) generics: works
let inline Add(p1: Nothing<'T>, p2: Nothing<'T>) = Nothing<_>(p1.X)
// SRTPs decalred only: works
let inline Add(p1: Nothing<(^T)>, p2: Nothing<(^T)>) = Nothing<_>(p1.X)
// SRTPs (requires member (+)), needs type annotation, slow (using AdditionDynamic, that is reflection), may fail at runtime (if no + operator)
let inline Add(p1: Nothing<(^T)>, p2: Nothing<(^T)>) = Nothing<_>(p1.X + p2.X)
// needs type annotation, guaranteed failure at runtime (no dynamic polyfill)
let inline Add(p1: Nothing<(^T)>, p2: Nothing<(^T)>) = Nothing<_>(p1.X %% p2.X)
现在,如果我们使用这些函数之一作为运算符,则只有非 SRTP 可以工作:
static member inline (*) (p1: Nothing<'T>, p2: Nothing<'T>) : Nothing<'T> = Nothing(p1.X) // fine
有 SRTP 声明就足够了:
static member inline (+) (p1: Nothing<(^a)>, p2: Nothing<(^a)>) : Nothing<(^a)> = Nothing(p1.X) // can not be used fom C#
这是为什么呢? C# 根本不支持泛型运算符(dotnet/csharplang 中有一些请求),而在 F# 中它们可以是内联
d。事实上,如果我们查看反编译的源代码:
// introduces new generic parameter `a`
public static Nothing<a> operator +(Nothing<a> p1, Nothing<a> p2)
// uses T from containing struct
public static Nothing<T> operator *(Nothing<T> p1, Nothing<T> p2)
'T when 'T: (static member (+): 'T * 'T -> 'T)
约束是在结构上还是操作符上没有区别:我们'll always end with a generic operator.
关于c# - 具有在 C# 中可见的算术运算符的 F# 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52779926/
我目前正在尝试基于哈希表构建字典。逻辑是:有一个名为 HashTable 的结构,其中包含以下内容: HashFunc HashFunc; PrintFunc PrintEntry; CompareF
如果我有一个指向结构/对象的指针,并且该结构/对象包含另外两个指向其他对象的指针,并且我想删除“包含这两个指针的对象而不破坏它所持有的指针”——我该怎么做这样做吗? 指向对象 A 的指针(包含指向对象
像这样的代码 package main import "fmt" type Hello struct { ID int Raw string } type World []*Hell
我有一个采用以下格式的 CSV: Module, Topic, Sub-topic 它需要能够导入到具有以下格式的 MySQL 数据库中: CREATE TABLE `modules` ( `id
通常我使用类似的东西 copy((uint8_t*)&POD, (uint8_t*)(&POD + 1 ), back_inserter(rawData)); copy((uint8_t*)&PODV
错误 : 联合只能在具有兼容列类型的表上执行。 结构(层:字符串,skyward_number:字符串,skyward_points:字符串)<> 结构(skyward_number:字符串,层:字符
我有一个指向结构的指针数组,我正在尝试使用它们进行 while 循环。我对如何准确初始化它并不完全有信心,但我一直这样做: Entry *newEntry = malloc(sizeof(Entry)
我正在学习 C,我的问题可能很愚蠢,但我很困惑。在这样的函数中: int afunction(somevariables) { if (someconditions)
我现在正在做一项编程作业,我并没有真正完全掌握链接,因为我们还没有涉及它。但是我觉得我需要它来做我想做的事情,因为数组还不够 我创建了一个结构,如下 struct node { float coef;
给定以下代码片段: #include #include #define MAX_SIZE 15 typedef struct{ int touchdowns; int intercepti
struct contact list[3]; int checknullarray() { for(int x=0;x<10;x++) { if(strlen(con
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Empty “for” loop in Facebook ajax what does AJAX call
我刚刚在反射器中浏览了一个文件,并在结构构造函数中看到了这个: this = new Binder.SyntaxNodeOrToken(); 我以前从未见过该术语。有人能解释一下这个赋值在 C# 中的
我经常使用字符串常量,例如: DICT_KEY1 = 'DICT_KEY1' DICT_KEY2 = 'DICT_KEY2' ... 很多时候我不介意实际的文字是什么,只要它们是独一无二的并且对人类读
我是 C 的新手,我不明白为什么下面的代码不起作用: typedef struct{ uint8_t a; uint8_t* b; } test_struct; test_struct
您能否制作一个行为类似于内置类之一的结构,您可以在其中直接分配值而无需调用属性? 前任: RoundedDouble count; count = 5; 而不是使用 RoundedDouble cou
这是我的代码: #include typedef struct { const char *description; float value; int age; } swag
在创建嵌套列表时,我认为 R 具有对列表元素有用的命名结构。我有一个列表列表,并希望应用包含在任何列表中的每个向量的函数。 lapply这样做但随后剥离了列表的命名结构。我该怎么办 lapply嵌套列
我正在做一个用于学习目的的个人组织者,我从来没有使用过 XML,所以我不确定我的解决方案是否是最好的。这是我附带的 XML 文件的基本结构:
我是新来的 nosql概念,所以当我开始学习时 PouchDB ,我找到了这个转换表。我的困惑是,如何PouchDB如果可以说我有多个表,是否意味着我需要创建多个数据库?因为根据我在 pouchdb
我是一名优秀的程序员,十分优秀!