自由范儿

文章 评论 浏览 27

自由范儿 2025-02-20 23:47:57

设置器和Getter必须使用相同的类型。

就您而言,要么是字符串或枚举。

一个人无法混合这些:

String get parity {} // STRING

set parity(SerialPortParity parity) {} // ENUM

考虑以下,功能性的代码,该代码也将两种类型都用于同一变量。

当人们定义具有不匹配类型的getter和setter时,这就是它看起来像飞镖的一样:

// Will not compile, as parity can be of one Type only.
class Abc {
  String parity;
  SerialPortParity parity;
}


var abc = Abc();
abc.partity = x;
var z = abc.partity;

Setter and Getter must use the same Type.

In your case, either a String or an Enum.

One cannot mix these:

String get parity {} // STRING

set parity(SerialPortParity parity) {} // ENUM

Consider the following, disfunctional code, which also uses both types for the same variable.

This is how it looks to Dart when one defines a Getter and Setter with not-matching Types:

// Will not compile, as parity can be of one Type only.
class Abc {
  String parity;
  SerialPortParity parity;
}


var abc = Abc();
abc.partity = x;
var z = abc.partity;

回报枚举时的回报类型的奇怪行为

自由范儿 2025-02-20 20:06:50

出于此特定目的(当您只有一个图像而不是图像时),您可以使用单一比例

enter image description herefor this specific purpose ( when you have only one image , not for icons ) , you can use single scale like this

我们可以跳过将图像放在1倍,2倍中,但仅放入3倍资产中。

自由范儿 2025-02-20 14:37:04

您的问题源于您正在使用现场注射,而不是使用基于构造函数的注入的最佳实践。除了您已经注意到的前者生产的代码很难测试的事实外,它还具有其他缺点。例如:

  1. 它不允许创建不变的组件(IE字段不是 final ),
  2. 它可能导致代码违反了单个责任原则(因为您很容易地注入了大量可能没有关注的依赖项
  3. )夫妻直接与DI容器直接使用代码(即,您不能轻松地在DI容器之外使用代码),
  4. 它可能会隐藏注射的依赖关系(即可选和必需之间没有明确的区分依赖项)。

基于所有这些,如果您使用构造函数注入来完成工作,那会更好。因此,将模拟注入服务的位置可以很容易地完成:


@Mock // The mock we need to inject
private MyMockedService mockedService;

@InjectMocks // The unit we need to test and inject mocks to
private MyUnitToTestServiceImpl unitToTestService;

或者,您可以使用实例化直接测试的设备,然后简单地通过其公共构造函数传递在模拟实例中。

因此,经验法则是在这种情况下始终使用构造函数注入。

Your problem stems from the fact that you are using field injection instead of the best practice which is to use constructor based injection. Aside from the fact that the former produces -- as you have noticed -- code that is hard to test, it has other drawbacks as well. For example:

  1. It disallows creating immutable components (i.e. fields are not final)
  2. It may lead to code that violates the Single Responsibility Principle (as you may easily inject a large number of dependencies that may go unoticed)
  3. It couples your code directly to the DI container (i.e. you cannot use your code outside of the DI container easily)
  4. It may hide injected dependencies (i.e. there is no clear differentiation between optional and required dependencies).

Based on all that, it would be better if you used constructor injection to do you job. With that in place injecting mocks into services can be done as easy as:


@Mock // The mock we need to inject
private MyMockedService mockedService;

@InjectMocks // The unit we need to test and inject mocks to
private MyUnitToTestServiceImpl unitToTestService;

Alternatively you can use instantiate the unit to be tested directly and simply pass in the mocked instance through its public constructor.

Thus the rule of thumb would be to always use constructor injection for such cases.

如何在@service中模拟spring @autowired webclient响应?

自由范儿 2025-02-20 12:47:52
  • 说我们考虑 swapexacttokensfortokens uniswapv2Router 的方法返回 uint []内存量
function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
  • 引用在这里 >
    这是我能够解决这个问题的方式:
  1. 在固体合同中,就在返回之前,我生成了一个包含即将返回的值的事件。
  2. 在Python代码中,我提取返回的值:
[...]
data = router.swapExactTokensForTokens(
        tokens[1].balanceOf(account),
        1,
        path,
        attacker,
        chain.time(),
        {"from": account},
    )

>>> int(web3.eth.getTransactionReceipt(data.txid)["logs"][2]["data"], 16)
631376138468681379
  • 这将为我们提供 MANES0OUT 的值。

  • 您可以看到 events 像这样

>>> data.events
{'Approval': [OrderedDict([('owner', '0x33A4622B82D4c04a53e170c638B944ce27cffce3'), ('spender', '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'), ('value', 4500000000000000000)])], 'Transfer': [OrderedDict([('from', '0x33A4622B82D4c04a53e170c638B944ce27cffce3'), ('to', '0xA68d9dd94574d286A75D39b1516b348620FfDCA0'), ('value', 500000000000000000)]), OrderedDict([('from', '0xA68d9dd94574d286A75D39b1516b348620FfDCA0'), ('to', '0x33A4622B82D4c04a53e170c638B944ce27cffce3'), ('value', 631376138468681379)])], 'Sync': [OrderedDict([('reserve0', 14368623861531318621), ('reserve1', 11844678011344678012)])], 'Swap': [OrderedDict([('sender', '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'), ('amount0In', 0), ('amount1In', 500000000000000000), ('amount0Out', 631376138468681379), ('amount1Out', 0), ('to', '0x33A4622B82D4c04a53e170c638B944ce27cffce3')])]}
  • 我正在使用 eth-brownie
  • Say we consider the swapExactTokensForTokens method of uniswapV2Router which returns uint[] memory amounts.
function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
  • Quoting from here
    Here is how I was able to resolve this problem:
  1. In the Solidity contract, just before returning, I generate an event which contains the value about to be returned.
  2. In the Python code, I extract the returned value with:
[...]
data = router.swapExactTokensForTokens(
        tokens[1].balanceOf(account),
        1,
        path,
        attacker,
        chain.time(),
        {"from": account},
    )

>>> int(web3.eth.getTransactionReceipt(data.txid)["logs"][2]["data"], 16)
631376138468681379
  • This will give us the value of amount0Out.

  • You can see the events like this

>>> data.events
{'Approval': [OrderedDict([('owner', '0x33A4622B82D4c04a53e170c638B944ce27cffce3'), ('spender', '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'), ('value', 4500000000000000000)])], 'Transfer': [OrderedDict([('from', '0x33A4622B82D4c04a53e170c638B944ce27cffce3'), ('to', '0xA68d9dd94574d286A75D39b1516b348620FfDCA0'), ('value', 500000000000000000)]), OrderedDict([('from', '0xA68d9dd94574d286A75D39b1516b348620FfDCA0'), ('to', '0x33A4622B82D4c04a53e170c638B944ce27cffce3'), ('value', 631376138468681379)])], 'Sync': [OrderedDict([('reserve0', 14368623861531318621), ('reserve1', 11844678011344678012)])], 'Swap': [OrderedDict([('sender', '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'), ('amount0In', 0), ('amount1In', 500000000000000000), ('amount0Out', 631376138468681379), ('amount1Out', 0), ('to', '0x33A4622B82D4c04a53e170c638B944ce27cffce3')])]}
  • I'm using eth-brownie.

如何将坚固合同功能的返回价值转换为Python中的列表?

自由范儿 2025-02-20 12:21:48

如果我理解问题是正确的,我会这样继续(Inline评论尝试解释逻辑),

// first we start the stream with the initial list of items (an array notified
// by the initialObservable)
initialObservable.pipe(
  // once initialObservable notifies the list we switch to another observable
  switchMap(items => {
    // the stream we switch to starts with the stream of mutations
    return mutationObservable.pipe(
      // we need to notify something since the very beginning, not only from
      // when the first mutation occurs, therefore we use startWith to say
      // that the new stream starts immediately notifying a null (assuming 
      // there is no null key in items)
      startWith(null),
      // since we need to keep a state but also to notify the state any time 
      // an event from upstream (i.e. a mutation) occurs, then we use the
      // scan operator which holds an internal state which is notified any time
      // upstream notifies something
      scan((state, m) => {
        // the state, i.e. the list of items, gets updated according to the
        //  mutations received from upstream
        state = state.filter(item => item.id !== m)
        // scan returns a new state
        return state
      }, items)  // the state is initialized with the items received
    )
  })
)

您可以看一下此stackblitz 示例。

If I understand the problem right, I would proceed like this (inline comments try to explain the logic)

// first we start the stream with the initial list of items (an array notified
// by the initialObservable)
initialObservable.pipe(
  // once initialObservable notifies the list we switch to another observable
  switchMap(items => {
    // the stream we switch to starts with the stream of mutations
    return mutationObservable.pipe(
      // we need to notify something since the very beginning, not only from
      // when the first mutation occurs, therefore we use startWith to say
      // that the new stream starts immediately notifying a null (assuming 
      // there is no null key in items)
      startWith(null),
      // since we need to keep a state but also to notify the state any time 
      // an event from upstream (i.e. a mutation) occurs, then we use the
      // scan operator which holds an internal state which is notified any time
      // upstream notifies something
      scan((state, m) => {
        // the state, i.e. the list of items, gets updated according to the
        //  mutations received from upstream
        state = state.filter(item => item.id !== m)
        // scan returns a new state
        return state
      }, items)  // the state is initialized with the items received
    )
  })
)

You can take a look at this stackblitz for an example.

在可观察的RXJS中管理内部状态

自由范儿 2025-02-20 02:56:40

问题似乎是 testscope.runtest 将等待所有儿童coroutines在提供测试结果之前完成。
执行不会陷入延迟(30_000)中。导致测试永远运行的原因是,您的断言失败并抛出了 essertionError 。由于抛出了错误,因此从未调用下一行 viewModel.onstop()。这意味着您在ViewModel中启动的Coroutine永远不会完成,因此 testscope.runtest 永远不会提供结果。
您可以轻松测试:

...
println("after delay; before assertion")
try{
    assertEquals(6, viewModel.count)
}catch (e: AssertionError){
    e.printStackTrace()
    throw e
}
println("after assertion")
viewModel.onStop()

最简单的解决方案是首先调用 viewmodel.onstop(),然后运行您想要的任何断言。


如果您关心一种完全替代方法,则可以避免完全手动开始和停止视图模式,然后选择更“ coroutine-y”的方法:


class AndroidTestViewModel(
    val injectedDispatcher: CoroutineDispatcher = Dispatchers.IO
) : ViewModel() {
    var count = 0

    suspend fun doWhileInForeground(){
        withContext(injectedDispatcher){
            while (true) {
                delay(5000)
                count++
            }
        }
    }
}

测试这可能会更像是这样:

@Test
fun interval() = scope.runTest {
    val viewModel = AndroidTestViewModel(injectedDispatcher)
    launch {
        viewModel.doWhileInForeground()
    }
    delay(30_000)
    assertEquals(6,viewModel.count)
}

并且在片段中使用了一个示例,这很容易适应活动或JetPack组成:

class SampleFragment: Fragment(){
    val viewModel: AndroidTestViewModel = TODO()
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch { 
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED){
                viewModel.doWhileInForeground()
            }
        }
    }
}

The problem appears to be that TestScope.runTest will wait for all child coroutines to complete before delivering test results.
The execution does not get stuck in delay(30_000). What causes the test to run forever is that your assertion fails and throws an AssertionError. Because an Error was thrown, the next line viewModel.onStop() is never called. This means the coroutine launched in your ViewModel never completes and hence TestScope.runTest will never deliver the result.
You can test this easily:

...
println("after delay; before assertion")
try{
    assertEquals(6, viewModel.count)
}catch (e: AssertionError){
    e.printStackTrace()
    throw e
}
println("after assertion")
viewModel.onStop()

The most simple solution would be to call viewModel.onStop() first, and then run whatever assertion you want to.


If you care for a completely alternative approach, you could avoid starting and stopping your viewmodel by hand altogether, and opt for a more "coroutine-y" way:


class AndroidTestViewModel(
    val injectedDispatcher: CoroutineDispatcher = Dispatchers.IO
) : ViewModel() {
    var count = 0

    suspend fun doWhileInForeground(){
        withContext(injectedDispatcher){
            while (true) {
                delay(5000)
                count++
            }
        }
    }
}

Testing this would probably look more like this:

@Test
fun interval() = scope.runTest {
    val viewModel = AndroidTestViewModel(injectedDispatcher)
    launch {
        viewModel.doWhileInForeground()
    }
    delay(30_000)
    assertEquals(6,viewModel.count)
}

And an example usage in a Fragment, this can be easily adapted to an Activity or jetpack compose:

class SampleFragment: Fragment(){
    val viewModel: AndroidTestViewModel = TODO()
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch { 
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED){
                viewModel.doWhileInForeground()
            }
        }
    }
}

测试无限Kotlin Coroutine

自由范儿 2025-02-19 17:24:57

您无法确定传递的数组内部功能的大小。您需要将大小作为附加参数传递。

const char array[] = {'t', 'h', 'i', 's', 'i', 's', 'm', 'y', 't', 'e', 'x', 't', 0};

void count_chars(const char *arr, unsigned int *counts, size_t size)
{
    for(size_t i = 0; i < size; i++)
        counts[(unsigned)arr[i]]++;
}

int main(void)
{
    int cnt[sizeof(array[0]) * (1 << CHAR_BIT)];

    count_chars(array, cnt, sizeof(array) / sizeof(array[0]));
}

您需要施放到无符号(不是 int ),因为 char> char 值可能为负。

You cant determine the size of the passed array inside function. You need to pass size as an additional parameter.

const char array[] = {'t', 'h', 'i', 's', 'i', 's', 'm', 'y', 't', 'e', 'x', 't', 0};

void count_chars(const char *arr, unsigned int *counts, size_t size)
{
    for(size_t i = 0; i < size; i++)
        counts[(unsigned)arr[i]]++;
}

int main(void)
{
    int cnt[sizeof(array[0]) * (1 << CHAR_BIT)];

    count_chars(array, cnt, sizeof(array) / sizeof(array[0]));
}

You need to cast to unsigned (not int) because char values can be negative.

C-计数数组长度的方法

自由范儿 2025-02-19 11:33:30

由于MongoDB版本4.4*,一个选项是将聚合管道与 $降低 $ mod $ filter $ zip

  1. $ ydre 带有 $ mod 添加一个新 mod 字段到每个项目,带有Value 0 每个奇数索引(1, 3,5,...)和值 1 偶数索引(2,4,6,...
  2. ) > mod value
  3. <代码> $ zip 这两个阵列到一对夫妻的数组,
db.collection.aggregate([
  {
    $project: {
      events: {
        $reduce: {
          input: "$events",
          initialValue: [],
          in: {$concatArrays: [
              "$value",
              [
                {
                  timestamp: "$this.timestamp",
                  status: "$this.status",
                  mod: {$mod: [{$size: "$value"}, 2]}
                }
              ]
            ]
          }
        }
      }
    }
  },
  {
    $project: {
      firstEvent: {$filter: {input: "$events", cond: {$eq: ["$this.mod", 0]}}},
      secondEvent: {$filter: {input: "$events", cond: {$eq: ["$this.mod", 1]}}}
    }
  },
  {$project: {couples: {$zip: {inputs: ["$firstEvent", "$secondEvent"]}}}}
])

看看它在 playground示例示例

*与较旧的mongodb版本,3.4或更高版本, $ mod 可以是替换为“手动” mod 计算。

Since mongoDB version 4.4*, One option is to use an aggregation pipeline with $reduce, $mod, $filter and $zip:

  1. $reduce with $mod to add a new mod field to each item, with value 0 to each odd index (1, 3, 5,...) and value 1 to each even index (2, 4, 6,...)
  2. $fiter into two arrays according to the mod value
  3. $zip these two arrays to one array of couples
db.collection.aggregate([
  {
    $project: {
      events: {
        $reduce: {
          input: "$events",
          initialValue: [],
          in: {$concatArrays: [
              "$value",
              [
                {
                  timestamp: "$this.timestamp",
                  status: "$this.status",
                  mod: {$mod: [{$size: "$value"}, 2]}
                }
              ]
            ]
          }
        }
      }
    }
  },
  {
    $project: {
      firstEvent: {$filter: {input: "$events", cond: {$eq: ["$this.mod", 0]}}},
      secondEvent: {$filter: {input: "$events", cond: {$eq: ["$this.mod", 1]}}}
    }
  },
  {$project: {couples: {$zip: {inputs: ["$firstEvent", "$secondEvent"]}}}}
])

See how it works on the playground example

*With older mongoDB versions, 3.4 or higher, the $mod can be replaces with a "manual" mod calculation.

如何在MongoDB的嵌套阵列上求发?

自由范儿 2025-02-19 08:58:01

这里的主要目标是编写类型函数类型schematotype&lt; t&gt; = ... 将架构类型作为输入,并产生相应的值类型作为输出。因此,您想要 schematotype&lt; {type:“ string”}&gt; be string ,以及 schematotype&lt; {type:“ array”,tyme:type:type:type:type: “ number”}}}&gt; be number [] 等。

首先,我们可能应该写一个 schema 键入该键模式类型可分配给。这不是严格必要的,如果愿意,您可以做不同的事情,但是这是一种方法:

type Schema = ObjectSchema | ArraySchema | PrimitiveSchema | OneOf | AnyOf;

type ObjectSchema = {
  type: "object",
  properties: Record<string, Schema>,
}

type ArraySchema = {
  type: "array",
  items: Schema,
}

interface PrimMapping {
  string: string,
  integer: number,
  number: number,
  // add here
}
    
type PrimitiveSchema = {
  type: keyof PrimMapping,
}

interface OneOf {
  oneOf: readonly Schema[]
}

interface AnyOf {
  anyOf: readonly Schema[]
}

当然,您可以使用其他模式类型来增强此定义。您可以看到架构联合特定架构类型的类型,其中一些( Objectschema arrayschema 单一 anyof )是按 schema 本身递归定义的。

我为什么要允许 /code>数组是因为它比常规读取阵列的限制类型较小,并且因为 /a>倾向于导致可读的元组类型。


因此,这是编写 schematotype&lt; t&gt; 的一种方法:

type SchemaToType<T extends Schema> =
  Schema extends T ? unknown :
  T extends OneOf ? SchemaToType<T['oneOf'][number]> :
  T extends AnyOf ? SchemaToType<T['anyOf'][number]> :
  T extends PrimitiveSchema ? PrimMapping[T['type']] :
  T extends ObjectSchema ? {
    - readonly [K in keyof T['properties']]: SchemaToType<T['properties'][K]>
  } :
  T extends ArraySchema ? SchemaToType<T['items']>[] :
  never;

这是递归条件类型。这个想法是,我们浏览每个 schema 联合成员并将其转换为相应的值类型。好吧,我们要做的第一件事是架构扩展t?未知:,这意味着如果 t 正是 schema 本身,我们将缩短计算并返回 the 未知类型。这种事情对于避免循环警告是必要的,因为否则 schematotype&lt; schema&gt; 最终将永远递归自己。

让我们看一下该类型的其他行:

  T extends OneOf ? SchemaToType<T['oneOf'][number]> :

如果 t Oneof ,那么我们需要 index Oneof 属性,该属性将是模式的数组...因此,我们将其进一步索引 number valued属性(提供数组元素类型)。 t ['Oneof'] [number] 将是数组中模式类型的结合。而且由于 schematotype 是(主要是)a 分配条件类型,然后 schematotype&lt; t ['Oneof'] [number]&gt; 本身将是该联合每个元素的价值类型的结合。所有这些都意味着输出类型将是所有 Oneof 数组元素值类型的联合。

  T extends AnyOf ? SchemaToType<T['anyOf'][number]> :

如果 t anyof ,我们与 Oneof 做同样的事情。大概您的架构在乎“任何”和“一个”和“一个”之间的区别,但是在打字稿中,这两者都以联盟为代表。如果您真的很关心差异,则可以使用 Oneof 构建一个“独家”联盟, 2887218“>这个问题,但我认为这是出于范围。

  T extends PrimitiveSchema ? PrimMapping[T['type']] :

这是简单的...我写了 primmapping 是来自 type 名称到原始类型的地图。因此,如果 t {type:“ integer”} ,则值类型为 primmapping [“ integer”] ,它被证明为号码

  T extends ObjectSchema ? {
    - readonly [K in keyof T['properties']]: SchemaToType<T['properties'][K]>
  } :

如果 t objectschema ,那么我们将映射类型 properties 属性上的每个键上的类型 t 。最后:

  T extends ArraySchema ? SchemaToType<T['items']>[] :

如果 t arrayschema ,那么我们将与 items 属性的类型进行数组>。


让我们测试一下:

const spec = {
  type: 'object',
  properties: {
    str: {
      type: 'string',
    },
    strOrNum: {
      oneOf: [{ type: 'string' }, { type: 'number' }],
      example: 30
    },
    strArr: {
      type: 'array',
      items: {
        type: 'string'
      }
    }
  }
} as const;

type SpecType = SchemaToType<typeof spec>
/* type SpecType = {
    str: string;
    strOrNum: string | number;
    strArr: string[];
} */

看起来不错!


当您实现某些函数或类方法,该函数或类方法是类型 schema 并产生示例时,您可能会遇到一些问题,使编译器可以推断出架构的正确类型。如果将上述 spec initializer不用作为const ,则编译器甚至不会记住特定的字面类型 类型属性和事物中断:

const specOops = {
  type: 'object',
  properties: {
    str: {
      type: 'string',
    },
    strOrNum: {
      oneOf: [{ type: 'string' }, { type: 'number' }],
      example: 30
    },
    strArr: {
      type: 'array',
      items: {
        type: 'string'
      }
    }
  }
} ;

type SpecTypeOops = SchemaToType<typeof specOops> // error!

因此,如果将事物保存到他们自己的变量中,则需要或类似的东西。

您可以以使编译器尝试从其输入中推断出狭窄类型的方式编写功能/方法,但这有点令人讨厌。请参阅 Microsoft/typeScript#30680 对于功能请求,可以更轻松地使其更容易。这是实现它的一种方法:

type SchemaHelper<T, K extends Types> = Schema & (
  { oneOf: readonly [] | readonly SchemaHelper<T, K>[] } |
  { anyOf: readonly [] | readonly SchemaHelper<T, K>[] } |
  {
    type: K,
    properties?: Record<string, SchemaHelper<T, K>>,
    items?: SchemaHelper<T, K>
  }
);

declare function schemaToExample<
  T extends SchemaHelper<T, K>, K extends Types
>(schema: T): SchemaToType<T>;

所有 schemahelper 确实是要求编译器注意 type 字面类型和单个数组类型和值。但是Yuck。

无论如何,让我们测试一下:

const ex2 = schemaToExample({
  type: 'object',
  properties: {
    firstName: {
      type: 'string',
      example: 'Johnbob',
    },
    lastName: {
      type: 'string',
      // No example provided
    },
    age: {
      type: 'integer',
      example: 30
    },
  }
});
/* const ex2: {
    firstName: string;
    lastName: string;
    age: number;
} */

const ex2a = schemaToExample({
  oneOf: [{
    type: 'object',
    properties: {
      name: {
        type: 'string',
        example: 'Beer'
      },
      liters: {
        type: 'integer',
        example: 1
      }
    }
  },
  {
    type: 'object',
    properties: {
      name: {
        type: 'string',
        example: 'Movie'
      },
      lengthInMins: {
        type: 'integer',
        example: 120
      }
    }
  }
  ]
}
);
/* const ex2a: {
    name: string;
    liters: number;
} | {
    name: string;
    lengthInMins: number;
} */

const ex3 = schemaToExample({
  type: 'object',
  properties: {
    firstName: {
      type: 'string',
      example: 'Johnbob',
    },
    lastName: {
      type: 'string',
      // No example provided
    },
    age: {
      type: 'integer',
      example: 30
    },
    favoriteThing: {
      oneOf: [{
        type: 'object',
        properties: {
          name: {
            type: 'string',
            example: 'Beer'
          },
          liters: {
            type: 'integer',
            example: 1
          }
        }
      },
      {
        type: 'object',
        properties: {
          name: {
            type: 'string',
            example: 'Movie'
          },
          lengthInMins: {
            type: 'integer',
            example: 120
          }
        }
      }
      ]
    }
  }
});
/* const ex3: {
    firstName: string;
    lastName: string;
    age: number;
    favoriteThing: {
        name: string;
        liters: number;
    } | {
        name: string;
        lengthInMins: number;
    };
} */

我认为看起来不错。输出类型是您想要的。

The main goal here is to write a type function type SchemaToType<T> = ... which takes a schema type as input and produces the corresponding value type as output. So you want SchemaToType<{type: "string"}> to be string, and SchemaToType<{type: "array", items: {type: "number"}}> to be number[], etc.

First we should probably write a Schema type that all schema types are assignable to. This isn't strictly necessary, and you can do it differently if you want, but here's one way to do it:

type Schema = ObjectSchema | ArraySchema | PrimitiveSchema | OneOf | AnyOf;

type ObjectSchema = {
  type: "object",
  properties: Record<string, Schema>,
}

type ArraySchema = {
  type: "array",
  items: Schema,
}

interface PrimMapping {
  string: string,
  integer: number,
  number: number,
  // add here
}
    
type PrimitiveSchema = {
  type: keyof PrimMapping,
}

interface OneOf {
  oneOf: readonly Schema[]
}

interface AnyOf {
  anyOf: readonly Schema[]
}

And of course you can augment this definition with other schema types. You can see that Schema is a union of specific schema types, some of which (ObjectSchema, ArraySchema, OneOf, and AnyOf) are recursively defined in terms of Schema itself.

The reason why I want to allow readonly arrays is because it is a less restrictive type than regular read-write arrays, and because const assertions tend to result in readonly tuple types.


Armed with that, here's one way to write SchemaToType<T>:

type SchemaToType<T extends Schema> =
  Schema extends T ? unknown :
  T extends OneOf ? SchemaToType<T['oneOf'][number]> :
  T extends AnyOf ? SchemaToType<T['anyOf'][number]> :
  T extends PrimitiveSchema ? PrimMapping[T['type']] :
  T extends ObjectSchema ? {
    - readonly [K in keyof T['properties']]: SchemaToType<T['properties'][K]>
  } :
  T extends ArraySchema ? SchemaToType<T['items']>[] :
  never;

This is a recursive conditional type. The idea is that we go through each Schema union member and convert it into the corresponding value type. Well, the first thing we do is Schema extends T ? unknown :, which means that if T turns out to be just Schema itself, we short-circuit the computation and return the unknown type. This sort of thing is necessary to avoid circularity warnings, since otherwise SchemaToType<Schema> would end up recursing into itself forever.

Let's look at the other lines of that type:

  T extends OneOf ? SchemaToType<T['oneOf'][number]> :

If T is a OneOf, then we need to index into its oneOf property, which is going to be an array of schemas... so we index further into its number-valued properties (which gives the array element type). T['oneOf'][number] will be a union of the schema types in the array. And since SchemaToType is (mostly) a distributive conditional type, then SchemaToType<T['oneOf'][number]> will itself be a union of the value types for each element of that union. All of this means that the output type will be a union of all the oneOf array element value types.

  T extends AnyOf ? SchemaToType<T['anyOf'][number]> :

If T is AnyOf, we do the same thing as OneOf. Presumably your schema cares about the difference between "any of" and "one of", but in TypeScript both of these are fairly well represented by a union. If you really care about the difference, you can build an "exclusive" union for OneOf, using a technique like that shown in this question, but I consider that out of scope here.

  T extends PrimitiveSchema ? PrimMapping[T['type']] :

This is the easy one... I wrote PrimMapping to be a map from type names to primitive types. So if T is {type: "integer"}, then the value type is PrimMapping["integer"], which turns out to be number.

  T extends ObjectSchema ? {
    - readonly [K in keyof T['properties']]: SchemaToType<T['properties'][K]>
  } :

If T is an ObjectSchema then we make a mapped type over each key from the properties property of T. And finally:

  T extends ArraySchema ? SchemaToType<T['items']>[] :

If T is an ArraySchema then we make an array of the type corresponding to the items property of T.


Let's test it out:

const spec = {
  type: 'object',
  properties: {
    str: {
      type: 'string',
    },
    strOrNum: {
      oneOf: [{ type: 'string' }, { type: 'number' }],
      example: 30
    },
    strArr: {
      type: 'array',
      items: {
        type: 'string'
      }
    }
  }
} as const;

type SpecType = SchemaToType<typeof spec>
/* type SpecType = {
    str: string;
    strOrNum: string | number;
    strArr: string[];
} */

Looks good!


When you come to implement some function or class method that takes a value of type Schema and produces an example, you might have some issues getting the compiler to infer the right type for the schema. If you write the above spec initializer without the as const, the compiler will fail to even remember the specific literal types of the type property and things break:

const specOops = {
  type: 'object',
  properties: {
    str: {
      type: 'string',
    },
    strOrNum: {
      oneOf: [{ type: 'string' }, { type: 'number' }],
      example: 30
    },
    strArr: {
      type: 'array',
      items: {
        type: 'string'
      }
    }
  }
} ;

type SpecTypeOops = SchemaToType<typeof specOops> // error!

So if you save things to their own variables you need as const or something like it.

You can write the function/method in such a way as to make the compiler try to infer narrow types from its input, but it's a bit obnoxious. See microsoft/TypeScript#30680 for a feature request to make it easier. Here's one way to implement it:

type SchemaHelper<T, K extends Types> = Schema & (
  { oneOf: readonly [] | readonly SchemaHelper<T, K>[] } |
  { anyOf: readonly [] | readonly SchemaHelper<T, K>[] } |
  {
    type: K,
    properties?: Record<string, SchemaHelper<T, K>>,
    items?: SchemaHelper<T, K>
  }
);

declare function schemaToExample<
  T extends SchemaHelper<T, K>, K extends Types
>(schema: T): SchemaToType<T>;

All SchemaHelper does is ask the compiler to pay attention to the type literal types and the individual array types and values. But yuck.

In any case, let's test it out:

const ex2 = schemaToExample({
  type: 'object',
  properties: {
    firstName: {
      type: 'string',
      example: 'Johnbob',
    },
    lastName: {
      type: 'string',
      // No example provided
    },
    age: {
      type: 'integer',
      example: 30
    },
  }
});
/* const ex2: {
    firstName: string;
    lastName: string;
    age: number;
} */

const ex2a = schemaToExample({
  oneOf: [{
    type: 'object',
    properties: {
      name: {
        type: 'string',
        example: 'Beer'
      },
      liters: {
        type: 'integer',
        example: 1
      }
    }
  },
  {
    type: 'object',
    properties: {
      name: {
        type: 'string',
        example: 'Movie'
      },
      lengthInMins: {
        type: 'integer',
        example: 120
      }
    }
  }
  ]
}
);
/* const ex2a: {
    name: string;
    liters: number;
} | {
    name: string;
    lengthInMins: number;
} */

const ex3 = schemaToExample({
  type: 'object',
  properties: {
    firstName: {
      type: 'string',
      example: 'Johnbob',
    },
    lastName: {
      type: 'string',
      // No example provided
    },
    age: {
      type: 'integer',
      example: 30
    },
    favoriteThing: {
      oneOf: [{
        type: 'object',
        properties: {
          name: {
            type: 'string',
            example: 'Beer'
          },
          liters: {
            type: 'integer',
            example: 1
          }
        }
      },
      {
        type: 'object',
        properties: {
          name: {
            type: 'string',
            example: 'Movie'
          },
          lengthInMins: {
            type: 'integer',
            example: 120
          }
        }
      }
      ]
    }
  }
});
/* const ex3: {
    firstName: string;
    lastName: string;
    age: number;
    favoriteThing: {
        name: string;
        liters: number;
    } | {
        name: string;
        lengthInMins: number;
    };
} */

Looks good, I think. The output types are the ones you wanted.

Playground link to code

推断构造对象的类型

自由范儿 2025-02-19 08:50:20

您可以使用Broom的增强(用于PC)和整理(用于加载)在 ggplot ing之前获取数据框:

library(tidyverse)
library(broom)

data <- tribble(
  ~Profession, ~il.count.ratio, ~elle.count.ratio, ~un.count.ratio, ~une.count.ratio,
  "secretary", 1.7241, 1.3514, 1.473, 0.7380,
  "secretary", 0.0000, 2.8736, 2.8536, 0.8370,
  "driver", 1.7065, 0.0000, 0.0000, 0.7380,
  "driver", 0.5284, 1.4733, 0.7380, 0.5280
)

data %>%
  select(il.count.ratio:une.count.ratio) %>%
  prcomp() %>% 
  augment(data) %>% 
  ggplot(aes(.fittedPC1, .fittedPC2, colour = Profession)) +
  geom_point()

“”

  
# Use instead of augment for the loadings
# tidy(matrix = "loadings")

在2022-06-30创建的 reprex软件包(v2.0.1)

You could use broom's augment (for the PCs) and tidy (for the loadings) to get a dataframe before ggploting:

library(tidyverse)
library(broom)

data <- tribble(
  ~Profession, ~il.count.ratio, ~elle.count.ratio, ~un.count.ratio, ~une.count.ratio,
  "secretary", 1.7241, 1.3514, 1.473, 0.7380,
  "secretary", 0.0000, 2.8736, 2.8536, 0.8370,
  "driver", 1.7065, 0.0000, 0.0000, 0.7380,
  "driver", 0.5284, 1.4733, 0.7380, 0.5280
)

data %>%
  select(il.count.ratio:une.count.ratio) %>%
  prcomp() %>% 
  augment(data) %>% 
  ggplot(aes(.fittedPC1, .fittedPC2, colour = Profession)) +
  geom_point()

  
# Use instead of augment for the loadings
# tidy(matrix = "loadings")

Created on 2022-06-30 by the reprex package (v2.0.1)

AutoPlot不支持PRCOMP类型的对象

自由范儿 2025-02-19 07:59:51

在Moodle中,您可以使用主题插件渲染器来渲染核心输出。
请参阅主题渲染器方法。

https://docs.moodle.org/dev/dev/overriding_a_renderer lib \ outputrenderers.php 第4340号线。
lib \ templates \ full_header.mustache 加载的完整标头的HTML内容

您可以使用当前运行的主题覆盖Full_header HTML内容。
以下步骤将帮助您更改完整的标题。

  1. 在当前运行主题“模板”文件夹中创建文件夹“ core”。
    IE 主题\ boost \ templates \ core

  2. 从lib \ templates文件夹中复制 full_header.mustache 到新创建的主题\ temot \ template \ core foldlate \ core文件夹。

  3. 进行主题\ templates \ full_header.mustache 文件

    的更改

  4. 进行 themplates \ full_header.mustache 文件

    清除 site admin&gt中的缓存

    ;开发&GT;吹扫库

In moodle, you can use the theme plugin renderers to render the core outputs.
Please refer to the theme renderer method.
https://docs.moodle.org/dev/Overriding_a_renderer

you can find the full_header function in lib\outputrenderers.php Line no 4340.
Html content of the full header loaded from lib\templates\full_header.mustache

You can override the full_header HTML content using the currently running theme.
The following steps will help you to change the full header.

  1. Create the folder "core" in the current running theme "templates" folder.
    i.e theme\boost\templates\core

  2. Copy the full_header.mustache from the lib\templates folder to the newly created theme\template\core folder.

  3. Do the changes in the theme\templates\full_header.mustache file

  4. Clear the cache in Site admin > development > purge caches

如何在不使用其他HTML框的情况下找到并编辑Moodle的HTML代码?

自由范儿 2025-02-19 06:24:11
df$Delta1 <- ifelse(!is.na(df$Time1) & !is.na(df$Time2) & !is.na(df$Time3),
                    df$Time2 - df$Time1,
                    NA)

df$Delta2 <- vapply(seq_len(nrow(df)), \(x){
                                              x = na.omit(c(df$Time3[x], df$Time2[x], df$Time1[x]))
                                              x = x[1] - x[2]
                                              if(is.na(x)) return(0)
                                              return(x)
                                            }, 0)

结果:

> df
  ID Type Time1 Time2 Time3 Delta1 Delta2
1  1   A1 12.23    NA    NA     NA   0.00
2  2   A1  0.35  0.53    NA     NA   0.18
3  2   A2  5.78    NA 10.25     NA   4.47
4  3   A5    NA    NA  4.19     NA   0.00
5  4   A3    NA  3.18  7.15     NA   3.97
6  5   A5 10.91  4.56  2.45  -6.35  -2.11
df$Delta1 <- ifelse(!is.na(df$Time1) & !is.na(df$Time2) & !is.na(df$Time3),
                    df$Time2 - df$Time1,
                    NA)

df$Delta2 <- vapply(seq_len(nrow(df)), \(x){
                                              x = na.omit(c(df$Time3[x], df$Time2[x], df$Time1[x]))
                                              x = x[1] - x[2]
                                              if(is.na(x)) return(0)
                                              return(x)
                                            }, 0)

Result:

> df
  ID Type Time1 Time2 Time3 Delta1 Delta2
1  1   A1 12.23    NA    NA     NA   0.00
2  2   A1  0.35  0.53    NA     NA   0.18
3  2   A2  5.78    NA 10.25     NA   4.47
4  3   A5    NA    NA  4.19     NA   0.00
5  4   A3    NA  3.18  7.15     NA   3.97
6  5   A5 10.91  4.56  2.45  -6.35  -2.11

基线列差

自由范儿 2025-02-19 02:10:57

tick()函数中,请勿调用 turtle.ontimer(tick,frame_delay_ms)在游戏结束时。您可以将该调用移至功能末尾,并设置一个确定是否应调用其的标志。

def tick():
    snake.move()
    screen.update()

    # Flag
    game_over = False

    # Detect Collision With Food
    if snake.head.distance(food) < 20:
        food.reset_food_location()
        snake.extend()
        scoreboard.increase_score()

    # Detect Collision With Wall
    if snake.head.xcor() == 300 or snake.head.xcor() == -300 \
            or snake.head.ycor() == 300 or snake.head.ycor() == -300:
        scoreboard.game_over()
        game_over = True   # Set flag

    # Detect Collision With Tail
    for segment in snake.segments[1:]:
        if snake.head.distance(segment) < 10:
            scoreboard.game_over()
            game_over = True   # Set flag
            break

    # Only call if game is NOT over
    if not game_over:
        turtle.ontimer(tick, frame_delay_ms)

In the tick() function, don't call turtle.ontimer(tick, frame_delay_ms) when the game is over. You can move that call to the end of the function and set a flag that determines whether or not it should be called.

def tick():
    snake.move()
    screen.update()

    # Flag
    game_over = False

    # Detect Collision With Food
    if snake.head.distance(food) < 20:
        food.reset_food_location()
        snake.extend()
        scoreboard.increase_score()

    # Detect Collision With Wall
    if snake.head.xcor() == 300 or snake.head.xcor() == -300 \
            or snake.head.ycor() == 300 or snake.head.ycor() == -300:
        scoreboard.game_over()
        game_over = True   # Set flag

    # Detect Collision With Tail
    for segment in snake.segments[1:]:
        if snake.head.distance(segment) < 10:
            scoreboard.game_over()
            game_over = True   # Set flag
            break

    # Only call if game is NOT over
    if not game_over:
        turtle.ontimer(tick, frame_delay_ms)

乌龟模块不允许我结束游戏

自由范儿 2025-02-18 04:32:03

您可以在打印出来之前使用Streams API进行排序:

Comparator<Entry<String, Map<String, Integer>>> entryComparator =
        Comparator.comparingInt((Entry<String, Map<String, Integer>> entryOne) -> entryOne.getValue().size());

    for(Entry<String, Map<String, Integer>> entry : states.entrySet().stream().sorted(entryComparator.reversed()).collect(
        Collectors.toList())) {
      System.out.println("State:" + entry.getKey());
      Map<String, Integer> tempMap = entry.getValue();
      for(Entry<String, Integer> innerEntry : tempMap.entrySet()) {
        System.out.println("City:" + innerEntry.getKey() + " Count:" + innerEntry.getValue());
      }

      System.out.println();
    }

You can use Streams API for sorting before print it out:

Comparator<Entry<String, Map<String, Integer>>> entryComparator =
        Comparator.comparingInt((Entry<String, Map<String, Integer>> entryOne) -> entryOne.getValue().size());

    for(Entry<String, Map<String, Integer>> entry : states.entrySet().stream().sorted(entryComparator.reversed()).collect(
        Collectors.toList())) {
      System.out.println("State:" + entry.getKey());
      Map<String, Integer> tempMap = entry.getValue();
      for(Entry<String, Integer> innerEntry : tempMap.entrySet()) {
        System.out.println("City:" + innerEntry.getKey() + " Count:" + innerEntry.getValue());
      }

      System.out.println();
    }

根据嵌套在给定的hashmap内部的每个hashmap的大小,按顺序打印hashmap的内容

自由范儿 2025-02-18 04:22:35

搜索网络我找不到答案或提示来解释错误消息。

转到另一个教程后,我了解了我的错误。

这是一个简单的“案例敏感”语法错误命名Docker文件的命名。

我将其命名为“ Dockerfile”,它应该被命名为“ Dockerfile”。

这是项目中所有其他文件名中的独特命名约定,它们都是小写或所有大写。

一条更好的错误消息将是“错误:丢失Dockerfile”,这足以让我找到原因。

Searching the web I could not find an answer or hint to explain the error message.

After moving on to another tutorial I understood what my mistake was.

It was a simple "case sensitive" syntax error naming of the docker file.

I named it "dockerfile" and it should have been named "Dockerfile".

This is a unique naming convention from all the other filenames in the project, they are either all lowercase or all uppercase.

A better error message would have been "ERROR: Missing Dockerfile", that would have been enough for me to find the cause.

enter image description here

gcloud运行部署错误:(gcloud.run.deploy)[来源]:指定时需要dockerfile的值

更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

更多

友情链接

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文